xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_rockusb.c (revision 47c8f13dc7bd0a8372ae8a5f4db7e2a73b786178)
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>
170d0c3248SFrank Wang 
180d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
190d0c3248SFrank Wang #include <asm/arch/vendor.h>
200d0c3248SFrank Wang #endif
21f16e43f8SFrank Wang #include <rockusb.h>
22f16e43f8SFrank Wang 
23f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS	0xff
24f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS	0x06
25f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL	0x05
26f16e43f8SFrank Wang 
27e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE	1024
28e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE	4
29e66d4537SJon Lin 
30f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = {
31f16e43f8SFrank Wang 	.bLength		= USB_DT_INTERFACE_SIZE,
32f16e43f8SFrank Wang 	.bDescriptorType	= USB_DT_INTERFACE,
33f16e43f8SFrank Wang 	.bInterfaceNumber	= 0x00,
34f16e43f8SFrank Wang 	.bAlternateSetting	= 0x00,
35f16e43f8SFrank Wang 	.bNumEndpoints		= 0x02,
36f16e43f8SFrank Wang 	.bInterfaceClass	= ROCKUSB_INTERFACE_CLASS,
37f16e43f8SFrank Wang 	.bInterfaceSubClass	= ROCKUSB_INTERFACE_SUB_CLASS,
38f16e43f8SFrank Wang 	.bInterfaceProtocol	= ROCKUSB_INTERFACE_PROTOCOL,
39f16e43f8SFrank Wang };
40f16e43f8SFrank Wang 
41f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = {
42f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
43f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_in_desc,
44f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_out_desc,
45f16e43f8SFrank Wang 	NULL,
46f16e43f8SFrank Wang };
47f16e43f8SFrank Wang 
48f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = {
49f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
50f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_in_desc,
51f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_out_desc,
52f16e43f8SFrank Wang 	NULL,
53f16e43f8SFrank Wang };
54f16e43f8SFrank Wang 
5526dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = {
5626dd3474SWilliam Wu 	(struct usb_descriptor_header *)&rkusb_intf_desc,
5726dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_desc,
5826dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc,
5926dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_desc,
6026dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc,
6126dd3474SWilliam Wu 	NULL,
6226dd3474SWilliam Wu };
6326dd3474SWilliam Wu 
64f16e43f8SFrank Wang struct rk_flash_info {
65f16e43f8SFrank Wang 	u32	flash_size;
66f16e43f8SFrank Wang 	u16	block_size;
67f16e43f8SFrank Wang 	u8	page_size;
68f16e43f8SFrank Wang 	u8	ecc_bits;
69f16e43f8SFrank Wang 	u8	access_time;
70f16e43f8SFrank Wang 	u8	manufacturer;
71f16e43f8SFrank Wang 	u8	flash_mask;
72f16e43f8SFrank Wang } __packed;
73f16e43f8SFrank Wang 
745b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
755b081643SFrank Wang 
76f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
77f16e43f8SFrank Wang {
78ba437c8cSFrank Wang 	if (IS_RKUSB_UMS_DNL(name)) {
79c0acb0f2SFrank Wang 		/* Fix to Rockchip's VID and PID */
80ba437c8cSFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x2207);
81ba437c8cSFrank Wang 		dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
82ba437c8cSFrank Wang 
83f16e43f8SFrank Wang 		/* Enumerate as a loader device */
8495424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG)
8595424692SJoseph Chen 		dev->bcdUSB = cpu_to_le16(0x0200);
8695424692SJoseph Chen #else
87f16e43f8SFrank Wang 		dev->bcdUSB = cpu_to_le16(0x0201);
8895424692SJoseph Chen #endif
89c0acb0f2SFrank Wang 	} else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
90c0acb0f2SFrank Wang 		/* Fix to Google's VID and PID */
91c0acb0f2SFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x18d1);
92c0acb0f2SFrank Wang 		dev->idProduct = __constant_cpu_to_le16(0xd00d);
93ca422507SYifeng Zhao 	} else if (!strncmp(name, "usb_dnl_dfu", 11)) {
94ca422507SYifeng Zhao 		/* Fix to Rockchip's VID and PID for DFU */
95ca422507SYifeng Zhao 		dev->idVendor  = cpu_to_le16(0x2207);
96ca422507SYifeng Zhao 		dev->idProduct = cpu_to_le16(0x0107);
970a076251SFrank Wang 	} else if (!strncmp(name, "usb_dnl_ums", 11)) {
980a076251SFrank Wang 		dev->idVendor  = cpu_to_le16(0x2207);
990a076251SFrank Wang 		dev->idProduct = cpu_to_le16(0x0010);
100ba437c8cSFrank Wang 	}
101f16e43f8SFrank Wang 
102f16e43f8SFrank Wang 	return 0;
103f16e43f8SFrank Wang }
104f16e43f8SFrank Wang 
105f16e43f8SFrank Wang __maybe_unused
106f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
107f16e43f8SFrank Wang {
108f16e43f8SFrank Wang 	assert(!cbw);
109f16e43f8SFrank Wang 
110f16e43f8SFrank Wang 	debug("%s:\n", __func__);
111f16e43f8SFrank Wang 	debug("Signature %x\n", cbw->Signature);
112f16e43f8SFrank Wang 	debug("Tag %x\n", cbw->Tag);
113f16e43f8SFrank Wang 	debug("DataTransferLength %x\n", cbw->DataTransferLength);
114f16e43f8SFrank Wang 	debug("Flags %x\n", cbw->Flags);
115f16e43f8SFrank Wang 	debug("LUN %x\n", cbw->Lun);
116f16e43f8SFrank Wang 	debug("Length %x\n", cbw->Length);
117f16e43f8SFrank Wang 	debug("OptionCode %x\n", cbw->CDB[0]);
118f16e43f8SFrank Wang 	debug("SubCode %x\n", cbw->CDB[1]);
119f16e43f8SFrank Wang 	debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
120f16e43f8SFrank Wang 	debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
121f16e43f8SFrank Wang }
122f16e43f8SFrank Wang 
123f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
124f16e43f8SFrank Wang {
125f16e43f8SFrank Wang 	struct fsg_lun *curlun;
126f16e43f8SFrank Wang 
127f16e43f8SFrank Wang 	/* Check the LUN */
128f16e43f8SFrank Wang 	if (common->lun >= 0 && common->lun < common->nluns) {
129f16e43f8SFrank Wang 		curlun = &common->luns[common->lun];
130f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_REQUEST_SENSE) {
131f16e43f8SFrank Wang 			curlun->sense_data = SS_NO_SENSE;
132f16e43f8SFrank Wang 			curlun->info_valid = 0;
133f16e43f8SFrank Wang 		}
134f16e43f8SFrank Wang 	} else {
135f16e43f8SFrank Wang 		curlun = NULL;
136f16e43f8SFrank Wang 		common->bad_lun_okay = 0;
137f16e43f8SFrank Wang 
138f16e43f8SFrank Wang 		/*
139f16e43f8SFrank Wang 		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
140f16e43f8SFrank Wang 		 * to use unsupported LUNs; all others may not.
141f16e43f8SFrank Wang 		 */
142f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_INQUIRY &&
143f16e43f8SFrank Wang 		    common->cmnd[0] != SC_REQUEST_SENSE) {
144f16e43f8SFrank Wang 			debug("unsupported LUN %d\n", common->lun);
145f16e43f8SFrank Wang 			return -EINVAL;
146f16e43f8SFrank Wang 		}
147f16e43f8SFrank Wang 	}
148f16e43f8SFrank Wang 
149f16e43f8SFrank Wang 	return 0;
150f16e43f8SFrank Wang }
151f16e43f8SFrank Wang 
152f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
153f16e43f8SFrank Wang {
1545b081643SFrank Wang 	u32 boot_flag = BOOT_NORMAL;
1555b081643SFrank Wang 
1565b081643SFrank Wang 	if (rkusb_rst_code == 0x03)
1575b081643SFrank Wang 		boot_flag = BOOT_BROM_DOWNLOAD;
1585b081643SFrank Wang 
1595b081643SFrank Wang 	rkusb_rst_code = 0; /* restore to default */
1605b081643SFrank Wang 	writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
161866d7966SJoseph Chen 
162f16e43f8SFrank Wang 	do_reset(NULL, 0, 0, NULL);
163f16e43f8SFrank Wang }
164f16e43f8SFrank Wang 
165f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
166f16e43f8SFrank Wang 			  struct fsg_buffhd *bh)
167f16e43f8SFrank Wang {
168f16e43f8SFrank Wang 	common->data_size_from_cmnd = common->cmnd[4];
169f16e43f8SFrank Wang 	common->residue = 0;
170f16e43f8SFrank Wang 	bh->inreq->complete = __do_reset;
171f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
172f16e43f8SFrank Wang 
1735b081643SFrank Wang 	rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
174f16e43f8SFrank Wang 	return 0;
175f16e43f8SFrank Wang }
176f16e43f8SFrank Wang 
177f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
178f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
179f16e43f8SFrank Wang {
1807eb64117SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
1817eb64117SJon Lin 
1827eb64117SJon Lin 	if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) ||
1837eb64117SJon Lin 	    desc->if_type == IF_TYPE_SPINOR)
1847eb64117SJon Lin 		common->residue = 0x03 << 24; /* 128KB Max block xfer for SPI Nor */
1857eb64117SJon Lin 	else
186f16e43f8SFrank Wang 		common->residue = 0x06 << 24; /* Max block xfer support from host */
1877eb64117SJon Lin 
188f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
189f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
190f16e43f8SFrank Wang 
191f16e43f8SFrank Wang 	return 0;
192f16e43f8SFrank Wang }
193f16e43f8SFrank Wang 
194f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
195f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
196f16e43f8SFrank Wang {
197f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
198e0023032SKever Yang 	u32 len = 5;
199d7386f60SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
200afc6362aSJon Lin 	u32 devnum = ums[common->lun].block_dev.devnum;
201afc6362aSJon Lin 	const char *str;
202f16e43f8SFrank Wang 
203afc6362aSJon Lin 	switch (type) {
204afc6362aSJon Lin 	case IF_TYPE_MMC:
205afc6362aSJon Lin 		str = "EMMC ";
206afc6362aSJon Lin 		break;
207afc6362aSJon Lin 	case IF_TYPE_RKNAND:
208afc6362aSJon Lin 		str = "NAND ";
209afc6362aSJon Lin 		break;
210afc6362aSJon Lin 	case IF_TYPE_MTD:
211afc6362aSJon Lin 		if (devnum == BLK_MTD_SPI_NAND)
212afc6362aSJon Lin 			str ="SNAND";
213afc6362aSJon Lin 		else if (devnum == BLK_MTD_NAND)
214afc6362aSJon Lin 			str = "NAND ";
215d7386f60SFrank Wang 		else
216afc6362aSJon Lin 			str = "NOR  ";
217afc6362aSJon Lin 		break;
218afc6362aSJon Lin 	default:
219afc6362aSJon Lin 		str = "UNKN "; /* unknown */
220afc6362aSJon Lin 		break;
221afc6362aSJon Lin 	}
222afc6362aSJon Lin 
223afc6362aSJon Lin 	memcpy((void *)&buf[0], str, len);
224f16e43f8SFrank Wang 
225f16e43f8SFrank Wang 	/* Set data xfer size */
226f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
227e0023032SKever Yang 	common->data_size = len;
228f16e43f8SFrank Wang 
229f16e43f8SFrank Wang 	return len;
230f16e43f8SFrank Wang }
231f16e43f8SFrank Wang 
232f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
233f16e43f8SFrank Wang 				   struct fsg_buffhd *bh)
234f16e43f8SFrank Wang {
235f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
236e0023032SKever Yang 	u32 len = 64;
237f16e43f8SFrank Wang 
238f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
239f16e43f8SFrank Wang 
240f16e43f8SFrank Wang 	/* Set data xfer size */
241f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
242e0023032SKever Yang 	common->data_size = len;
243f16e43f8SFrank Wang 
244f16e43f8SFrank Wang 	return len;
245f16e43f8SFrank Wang }
246f16e43f8SFrank Wang 
247f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
248f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
249f16e43f8SFrank Wang {
250e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
251f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
252d23ec8c4SKever Yang 	u32 len = sizeof(struct rk_flash_info);
253f16e43f8SFrank Wang 	struct rk_flash_info finfo = {
254e66d4537SJon Lin 		.block_size = ROCKCHIP_FLASH_BLOCK_SIZE,
255f16e43f8SFrank Wang 		.ecc_bits = 0,
256e66d4537SJon Lin 		.page_size = ROCKCHIP_FLASH_PAGE_SIZE,
257f16e43f8SFrank Wang 		.access_time = 40,
258f16e43f8SFrank Wang 		.manufacturer = 0,
259f16e43f8SFrank Wang 		.flash_mask = 0
260f16e43f8SFrank Wang 	};
261f16e43f8SFrank Wang 
262e66d4537SJon Lin 	finfo.flash_size = (u32)desc->lba;
263e66d4537SJon Lin 
264e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
265e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
266e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
267e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
268e66d4537SJon Lin 
269e66d4537SJon Lin 		if (mtd) {
270e66d4537SJon Lin 			finfo.block_size = mtd->erasesize >> 9;
271e66d4537SJon Lin 			finfo.page_size = mtd->writesize >> 9;
272e66d4537SJon Lin 		}
273e66d4537SJon Lin 	}
274e66d4537SJon Lin 
27565a0fed9SJon Lin 	if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) {
27665a0fed9SJon Lin 		/* RV1126/RK3308 mtd spinor keep the former upgrade mode */
27765a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308)
278b8e5601dSJon Lin 		finfo.block_size = 0x80; /* Aligned to 64KB */
27965a0fed9SJon Lin #else
28065a0fed9SJon Lin 		finfo.block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
28165a0fed9SJon Lin #endif
28265a0fed9SJon Lin 	}
28365a0fed9SJon Lin 
284e66d4537SJon Lin 	debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size,
285e66d4537SJon Lin 	      finfo.page_size);
286e66d4537SJon Lin 
287f16e43f8SFrank Wang 	if (finfo.flash_size)
288f16e43f8SFrank Wang 		finfo.flash_mask = 1;
289f16e43f8SFrank Wang 
290f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
291f16e43f8SFrank Wang 	memcpy((void *)&buf[0], (void *)&finfo, len);
292f16e43f8SFrank Wang 
293f16e43f8SFrank Wang 	/* Set data xfer size */
294f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
295d23ec8c4SKever Yang         /* legacy upgrade_tool does not set correct transfer size */
296d23ec8c4SKever Yang 	common->data_size = len;
297f16e43f8SFrank Wang 
298f16e43f8SFrank Wang 	return len;
299f16e43f8SFrank Wang }
300f16e43f8SFrank Wang 
301829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
302829f2b85SFrank Wang 				  struct fsg_buffhd *bh)
303829f2b85SFrank Wang {
304829f2b85SFrank Wang 	u8 *buf = (u8 *)bh->buf;
305829f2b85SFrank Wang 	u32 len = common->data_size;
306829f2b85SFrank Wang 	u32 chip_info[4];
307829f2b85SFrank Wang 
308829f2b85SFrank Wang 	memset((void *)chip_info, 0, sizeof(chip_info));
309829f2b85SFrank Wang 	rockchip_rockusb_get_chip_info(chip_info);
310829f2b85SFrank Wang 
311829f2b85SFrank Wang 	memset((void *)&buf[0], 0, len);
312829f2b85SFrank Wang 	memcpy((void *)&buf[0], (void *)chip_info, len);
313829f2b85SFrank Wang 
314829f2b85SFrank Wang 	/* Set data xfer size */
315829f2b85SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
316829f2b85SFrank Wang 
317829f2b85SFrank Wang 	return len;
318829f2b85SFrank Wang }
319829f2b85SFrank Wang 
320f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
321f16e43f8SFrank Wang 			      struct fsg_buffhd *bh)
322f16e43f8SFrank Wang {
323f16e43f8SFrank Wang 	struct fsg_lun *curlun = &common->luns[common->lun];
324f16e43f8SFrank Wang 	u32 lba, amount;
325f16e43f8SFrank Wang 	loff_t file_offset;
326f16e43f8SFrank Wang 	int rc;
327f16e43f8SFrank Wang 
328f16e43f8SFrank Wang 	lba = get_unaligned_be32(&common->cmnd[2]);
329f16e43f8SFrank Wang 	if (lba >= curlun->num_sectors) {
330f16e43f8SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
331f16e43f8SFrank Wang 		rc = -EINVAL;
332f16e43f8SFrank Wang 		goto out;
333f16e43f8SFrank Wang 	}
334f16e43f8SFrank Wang 
335f16e43f8SFrank Wang 	file_offset = ((loff_t) lba) << 9;
336f16e43f8SFrank Wang 	amount = get_unaligned_be16(&common->cmnd[7]) << 9;
337f16e43f8SFrank Wang 	if (unlikely(amount == 0)) {
338f16e43f8SFrank Wang 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
339f16e43f8SFrank Wang 		rc = -EIO;
340f16e43f8SFrank Wang 		goto out;
341f16e43f8SFrank Wang 	}
342f16e43f8SFrank Wang 
343f16e43f8SFrank Wang 	/* Perform the erase */
344f16e43f8SFrank Wang 	rc = ums[common->lun].erase_sector(&ums[common->lun],
345f16e43f8SFrank Wang 			       file_offset / SECTOR_SIZE,
346f16e43f8SFrank Wang 			       amount / SECTOR_SIZE);
347f16e43f8SFrank Wang 	if (!rc) {
348f16e43f8SFrank Wang 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
349f16e43f8SFrank Wang 		rc = -EIO;
350f16e43f8SFrank Wang 	}
351f16e43f8SFrank Wang 
352f16e43f8SFrank Wang out:
353f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
354f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
355f16e43f8SFrank Wang 
356f16e43f8SFrank Wang 	return rc;
357f16e43f8SFrank Wang }
358f16e43f8SFrank Wang 
359e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common,
360e66d4537SJon Lin 				struct fsg_buffhd *bh)
361e66d4537SJon Lin {
362e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
363e66d4537SJon Lin 	struct fsg_lun *curlun = &common->luns[common->lun];
364e66d4537SJon Lin 	u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
365e66d4537SJon Lin 	u32 lba, amount;
366e66d4537SJon Lin 	loff_t file_offset;
367e66d4537SJon Lin 	int rc;
368e66d4537SJon Lin 
369e66d4537SJon Lin 	lba = get_unaligned_be32(&common->cmnd[2]);
370e66d4537SJon Lin 	if (lba >= curlun->num_sectors) {
371e66d4537SJon Lin 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
372e66d4537SJon Lin 		rc = -EINVAL;
373e66d4537SJon Lin 		goto out;
374e66d4537SJon Lin 	}
375e66d4537SJon Lin 
376e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
377e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
378e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
379e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
380e66d4537SJon Lin 
381e66d4537SJon Lin 		if (mtd)
382e66d4537SJon Lin 			block_size = mtd->erasesize >> 9;
383e66d4537SJon Lin 	}
384e66d4537SJon Lin 
385e66d4537SJon Lin 	file_offset = ((loff_t)lba) * block_size;
386e66d4537SJon Lin 	amount = get_unaligned_be16(&common->cmnd[7]) * block_size;
387e66d4537SJon Lin 
388e66d4537SJon Lin 	debug("%s lba= %x, nsec= %x\n", __func__, lba,
389e66d4537SJon Lin 	      (u32)get_unaligned_be16(&common->cmnd[7]));
390e66d4537SJon Lin 
391e66d4537SJon Lin 	if (unlikely(amount == 0)) {
392e66d4537SJon Lin 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
393e66d4537SJon Lin 		rc = -EIO;
394e66d4537SJon Lin 		goto out;
395e66d4537SJon Lin 	}
396e66d4537SJon Lin 
397e66d4537SJon Lin 	/* Perform the erase */
398e66d4537SJon Lin 	rc = ums[common->lun].erase_sector(&ums[common->lun],
399e66d4537SJon Lin 					   file_offset,
400e66d4537SJon Lin 					   amount);
401e66d4537SJon Lin 	if (!rc) {
402e66d4537SJon Lin 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
403e66d4537SJon Lin 		rc = -EIO;
404e66d4537SJon Lin 	}
405e66d4537SJon Lin 
406e66d4537SJon Lin out:
407e66d4537SJon Lin 	common->data_dir = DATA_DIR_NONE;
408e66d4537SJon Lin 	bh->state = BUF_STATE_EMPTY;
409e66d4537SJon Lin 
410e66d4537SJon Lin 	return rc;
411e66d4537SJon Lin }
412e66d4537SJon Lin 
4130d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
4140d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
4150d0c3248SFrank Wang {
4160d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
4170d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
4180d0c3248SFrank Wang 	struct vendor_item	*vhead;
4190d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
4200d0c3248SFrank Wang 	void			*data;
4210d0c3248SFrank Wang 	int			rc;
4220d0c3248SFrank Wang 
4230d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
4240d0c3248SFrank Wang 		/* _MUST_ small than 64K */
4250d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
4260d0c3248SFrank Wang 		return -EINVAL;
4270d0c3248SFrank Wang 	}
4280d0c3248SFrank Wang 
4290d0c3248SFrank Wang 	common->residue         = common->data_size;
4300d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
4310d0c3248SFrank Wang 
4320d0c3248SFrank Wang 	/* Carry out the file writes */
4330d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
4340d0c3248SFrank Wang 		return -EIO; /* No data to write */
4350d0c3248SFrank Wang 
4360d0c3248SFrank Wang 	for (;;) {
4370d0c3248SFrank Wang 		if (common->usb_amount_left > 0) {
4380d0c3248SFrank Wang 			/* Wait for the next buffer to become available */
4390d0c3248SFrank Wang 			bh = common->next_buffhd_to_fill;
4400d0c3248SFrank Wang 			if (bh->state != BUF_STATE_EMPTY)
4410d0c3248SFrank Wang 				goto wait;
4420d0c3248SFrank Wang 
4430d0c3248SFrank Wang 			/* Request the next buffer */
4440d0c3248SFrank Wang 			common->usb_amount_left      -= common->data_size;
4450d0c3248SFrank Wang 			bh->outreq->length	     = common->data_size;
4460d0c3248SFrank Wang 			bh->bulk_out_intended_length = common->data_size;
4470d0c3248SFrank Wang 			bh->outreq->short_not_ok     = 1;
4480d0c3248SFrank Wang 
4490d0c3248SFrank Wang 			START_TRANSFER_OR(common, bulk_out, bh->outreq,
4500d0c3248SFrank Wang 					  &bh->outreq_busy, &bh->state)
4510d0c3248SFrank Wang 				/*
4520d0c3248SFrank Wang 				 * Don't know what to do if
4530d0c3248SFrank Wang 				 * common->fsg is NULL
4540d0c3248SFrank Wang 				 */
4550d0c3248SFrank Wang 				return -EIO;
4560d0c3248SFrank Wang 			common->next_buffhd_to_fill = bh->next;
4570d0c3248SFrank Wang 		} else {
4580d0c3248SFrank Wang 			/* Then, wait for the data to become available */
4590d0c3248SFrank Wang 			bh = common->next_buffhd_to_drain;
4600d0c3248SFrank Wang 			if (bh->state != BUF_STATE_FULL)
4610d0c3248SFrank Wang 				goto wait;
4620d0c3248SFrank Wang 
4630d0c3248SFrank Wang 			common->next_buffhd_to_drain = bh->next;
4640d0c3248SFrank Wang 			bh->state = BUF_STATE_EMPTY;
4650d0c3248SFrank Wang 
4660d0c3248SFrank Wang 			/* Did something go wrong with the transfer? */
4670d0c3248SFrank Wang 			if (bh->outreq->status != 0) {
4680d0c3248SFrank Wang 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
4690d0c3248SFrank Wang 				curlun->info_valid = 1;
4700d0c3248SFrank Wang 				break;
4710d0c3248SFrank Wang 			}
4720d0c3248SFrank Wang 
4730d0c3248SFrank Wang 			/* Perform the write */
4740d0c3248SFrank Wang 			vhead = (struct vendor_item *)bh->buf;
4750d0c3248SFrank Wang 			data  = bh->buf + sizeof(struct vendor_item);
4760d0c3248SFrank Wang 
4770d0c3248SFrank Wang 			if (!type) {
478420ee9d5SJoseph Chen 				if (vhead->id == HDCP_14_HDMI_ID ||
47978dcc928SZhang Yubing 				    vhead->id == HDCP_14_HDMIRX_ID ||
48078dcc928SZhang Yubing 				    vhead->id == HDCP_14_DP_ID) {
481420ee9d5SJoseph Chen 					rc = vendor_handle_hdcp(vhead);
482420ee9d5SJoseph Chen 					if (rc < 0) {
483420ee9d5SJoseph Chen 						curlun->sense_data = SS_WRITE_ERROR;
484420ee9d5SJoseph Chen 						return -EIO;
485420ee9d5SJoseph Chen 					}
486420ee9d5SJoseph Chen 				}
487420ee9d5SJoseph Chen 
4880d0c3248SFrank Wang 				/* Vendor storage */
4890d0c3248SFrank Wang 				rc = vendor_storage_write(vhead->id,
4900d0c3248SFrank Wang 							  (char __user *)data,
4910d0c3248SFrank Wang 							  vhead->size);
49219652be0SFrank Wang 				if (rc < 0) {
49319652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
4940d0c3248SFrank Wang 					return -EIO;
49519652be0SFrank Wang 				}
4962122174dSWu Liangqing 			} else if (type == 1) {
4970d0c3248SFrank Wang 				/* RPMB */
4986f0347c8Stony.xu 				rc =
4996f0347c8Stony.xu 				write_keybox_to_secure_storage((u8 *)data,
5006f0347c8Stony.xu 							       vhead->size);
50119652be0SFrank Wang 				if (rc < 0) {
50219652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
5036f0347c8Stony.xu 					return -EIO;
5040d0c3248SFrank Wang 				}
5052122174dSWu Liangqing 			} else if (type == 2) {
5062122174dSWu Liangqing 				/* security storage */
5072122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
5082122174dSWu Liangqing 				debug("%s call rk_avb_write_perm_attr %d, %d\n",
5092122174dSWu Liangqing 				      __func__, vhead->id, vhead->size);
5102122174dSWu Liangqing 				rc = rk_avb_write_perm_attr(vhead->id,
5112122174dSWu Liangqing 							    (char __user *)data,
5122122174dSWu Liangqing 							    vhead->size);
5132122174dSWu Liangqing 				if (rc < 0) {
5142122174dSWu Liangqing 					curlun->sense_data = SS_WRITE_ERROR;
5152122174dSWu Liangqing 					return -EIO;
5162122174dSWu Liangqing 				}
5172122174dSWu Liangqing #else
5182122174dSWu Liangqing 				printf("Please enable CONFIG_RK_AVB_LIBAVB_USER\n");
5192122174dSWu Liangqing #endif
520850ced9dSHisping Lin 			} else if (type == 3) {
521850ced9dSHisping Lin 				/* efuse or otp*/
522850ced9dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
523850ced9dSHisping Lin 				if (memcmp(data, "TAEK", 4) == 0) {
524850ced9dSHisping Lin 					if (vhead->size - 8 != 32) {
525850ced9dSHisping Lin 						printf("check ta encryption key size fail!\n");
526850ced9dSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
527850ced9dSHisping Lin 						return -EIO;
528850ced9dSHisping Lin 					}
529850ced9dSHisping Lin 					if (trusty_write_ta_encryption_key((uint32_t *)(data + 8), 8) != 0) {
530850ced9dSHisping Lin 						printf("trusty_write_ta_encryption_key error!");
531850ced9dSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
532850ced9dSHisping Lin 						return -EIO;
533850ced9dSHisping Lin 					}
534a43611afSHisping Lin 				} else if (memcmp(data, "EHUK", 4) == 0) {
535a43611afSHisping Lin 					if (vhead->size - 8 != 32) {
536a43611afSHisping Lin 						printf("check oem huk size fail!\n");
537a43611afSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
538a43611afSHisping Lin 						return -EIO;
539a43611afSHisping Lin 					}
540a43611afSHisping Lin 					if (trusty_write_oem_huk((uint32_t *)(data + 8), 8) != 0) {
541a43611afSHisping Lin 						printf("trusty_write_oem_huk error!");
542a43611afSHisping Lin 						curlun->sense_data = SS_WRITE_ERROR;
543a43611afSHisping Lin 						return -EIO;
544a43611afSHisping Lin 					}
545850ced9dSHisping Lin 				} else {
546850ced9dSHisping Lin 					printf("Unknown tag\n");
547850ced9dSHisping Lin 					curlun->sense_data = SS_WRITE_ERROR;
548850ced9dSHisping Lin 					return -EIO;
549850ced9dSHisping Lin 				}
550850ced9dSHisping Lin #else
551850ced9dSHisping Lin 				printf("Please enable CONFIG_OPTEE_CLIENT\n");
552850ced9dSHisping Lin #endif
5532122174dSWu Liangqing 			} else {
5542122174dSWu Liangqing 				return -EINVAL;
55519652be0SFrank Wang 			}
5560d0c3248SFrank Wang 
5570d0c3248SFrank Wang 			common->residue -= common->data_size;
5580d0c3248SFrank Wang 
5590d0c3248SFrank Wang 			/* Did the host decide to stop early? */
5600d0c3248SFrank Wang 			if (bh->outreq->actual != bh->outreq->length)
5610d0c3248SFrank Wang 				common->short_packet_received = 1;
5620d0c3248SFrank Wang 			break; /* Command done */
5630d0c3248SFrank Wang 		}
5640d0c3248SFrank Wang wait:
5650d0c3248SFrank Wang 		/* Wait for something to happen */
5660d0c3248SFrank Wang 		rc = sleep_thread(common);
5670d0c3248SFrank Wang 		if (rc)
5680d0c3248SFrank Wang 			return rc;
5690d0c3248SFrank Wang 	}
5700d0c3248SFrank Wang 
5710d0c3248SFrank Wang 	return -EIO; /* No default reply */
5720d0c3248SFrank Wang }
5730d0c3248SFrank Wang 
5740d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
5750d0c3248SFrank Wang {
5760d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
5770d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
5780d0c3248SFrank Wang 	struct vendor_item	*vhead;
5790d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
5800d0c3248SFrank Wang 	void			*data;
5810d0c3248SFrank Wang 	int			rc;
5820d0c3248SFrank Wang 
5830d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
5840d0c3248SFrank Wang 		/* _MUST_ small than 64K */
5850d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
5860d0c3248SFrank Wang 		return -EINVAL;
5870d0c3248SFrank Wang 	}
5880d0c3248SFrank Wang 
5890d0c3248SFrank Wang 	common->residue         = common->data_size;
5900d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
5910d0c3248SFrank Wang 
5920d0c3248SFrank Wang 	/* Carry out the file reads */
5930d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
5940d0c3248SFrank Wang 		return -EIO; /* No default reply */
5950d0c3248SFrank Wang 
5960d0c3248SFrank Wang 	for (;;) {
5970d0c3248SFrank Wang 		/* Wait for the next buffer to become available */
5980d0c3248SFrank Wang 		bh = common->next_buffhd_to_fill;
5990d0c3248SFrank Wang 		while (bh->state != BUF_STATE_EMPTY) {
6000d0c3248SFrank Wang 			rc = sleep_thread(common);
6010d0c3248SFrank Wang 			if (rc)
6020d0c3248SFrank Wang 				return rc;
6030d0c3248SFrank Wang 		}
6040d0c3248SFrank Wang 
6050d0c3248SFrank Wang 		memset(bh->buf, 0, FSG_BUFLEN);
6060d0c3248SFrank Wang 		vhead = (struct vendor_item *)bh->buf;
6070d0c3248SFrank Wang 		data  = bh->buf + sizeof(struct vendor_item);
6080d0c3248SFrank Wang 		vhead->id = get_unaligned_be16(&common->cmnd[2]);
6090d0c3248SFrank Wang 
6100d0c3248SFrank Wang 		if (!type) {
6110d0c3248SFrank Wang 			/* Vendor storage */
6120d0c3248SFrank Wang 			rc = vendor_storage_read(vhead->id,
6130d0c3248SFrank Wang 						 (char __user *)data,
6140d0c3248SFrank Wang 						 common->data_size);
61519652be0SFrank Wang 			if (!rc) {
61619652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
6170d0c3248SFrank Wang 				return -EIO;
61819652be0SFrank Wang 			}
6190d0c3248SFrank Wang 			vhead->size = rc;
6202122174dSWu Liangqing 		} else if (type == 1) {
6210d0c3248SFrank Wang 			/* RPMB */
622700a3668STony Xu 			rc =
623700a3668STony Xu 			read_raw_data_from_secure_storage((u8 *)data,
624700a3668STony Xu 							  common->data_size);
62519652be0SFrank Wang 			if (!rc) {
62619652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
627700a3668STony Xu 				return -EIO;
62819652be0SFrank Wang 			}
629700a3668STony Xu 			vhead->size = rc;
6302122174dSWu Liangqing 		} else if (type == 2) {
6312122174dSWu Liangqing 			/* security storage */
6322122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
6332122174dSWu Liangqing 			rc = rk_avb_read_perm_attr(vhead->id,
6342122174dSWu Liangqing 						   (char __user *)data,
6352122174dSWu Liangqing 						   vhead->size);
6362122174dSWu Liangqing 			if (rc < 0)
6372122174dSWu Liangqing 				return -EIO;
6382122174dSWu Liangqing 			vhead->size = rc;
6392122174dSWu Liangqing #else
6402122174dSWu Liangqing 			printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n");
6412122174dSWu Liangqing #endif
642*47c8f13dSHisping Lin 		} else if (type == 3) {
643*47c8f13dSHisping Lin 			/* efuse or otp*/
644*47c8f13dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
645*47c8f13dSHisping Lin 			if (vhead->id == 120) {
646*47c8f13dSHisping Lin 				u8 value;
647*47c8f13dSHisping Lin 				char *written_str = "key is written!";
648*47c8f13dSHisping Lin 				char *not_written_str = "key is not written!";
649*47c8f13dSHisping Lin 				if (trusty_ta_encryption_key_is_written(&value) != 0) {
650*47c8f13dSHisping Lin 					printf("trusty_ta_encryption_key_is_written error!");
651*47c8f13dSHisping Lin 					return -EIO;
652*47c8f13dSHisping Lin 				}
653*47c8f13dSHisping Lin 				if (value) {
654*47c8f13dSHisping Lin 					memcpy(data, written_str, strlen(written_str));
655*47c8f13dSHisping Lin 					vhead->size = strlen(written_str);
656*47c8f13dSHisping Lin 				} else {
657*47c8f13dSHisping Lin 					memcpy(data, not_written_str, strlen(not_written_str));
658*47c8f13dSHisping Lin 					vhead->size = strlen(not_written_str);
659*47c8f13dSHisping Lin 				}
660*47c8f13dSHisping Lin 			} else {
661*47c8f13dSHisping Lin 				printf("Unknown tag\n");
662*47c8f13dSHisping Lin 				return -EIO;
663*47c8f13dSHisping Lin 			}
664*47c8f13dSHisping Lin #else
665*47c8f13dSHisping Lin 			printf("Please enable CONFIG_OPTEE_CLIENT\n");
666*47c8f13dSHisping Lin #endif
6672122174dSWu Liangqing 		} else {
6682122174dSWu Liangqing 			return -EINVAL;
6690d0c3248SFrank Wang 		}
6700d0c3248SFrank Wang 
6710d0c3248SFrank Wang 		common->residue   -= common->data_size;
6720d0c3248SFrank Wang 		bh->inreq->length = common->data_size;
6730d0c3248SFrank Wang 		bh->state         = BUF_STATE_FULL;
6740d0c3248SFrank Wang 
6750d0c3248SFrank Wang 		break; /* No more left to read */
6760d0c3248SFrank Wang 	}
6770d0c3248SFrank Wang 
6780d0c3248SFrank Wang 	return -EIO; /* No default reply */
6790d0c3248SFrank Wang }
6800d0c3248SFrank Wang #endif
6810d0c3248SFrank Wang 
682d4cce25eSYifeng Zhao static int rkusb_do_get_storage_info(struct fsg_common *common,
683d4cce25eSYifeng Zhao 				     struct fsg_buffhd *bh)
684d4cce25eSYifeng Zhao {
685d4cce25eSYifeng Zhao 	enum if_type type = ums[common->lun].block_dev.if_type;
686d4cce25eSYifeng Zhao 	int devnum = ums[common->lun].block_dev.devnum;
687d4cce25eSYifeng Zhao 	u32 media = BOOT_TYPE_UNKNOWN;
688d4cce25eSYifeng Zhao 	u32 len = common->data_size;
689d4cce25eSYifeng Zhao 	u8 *buf = (u8 *)bh->buf;
690d4cce25eSYifeng Zhao 
691d4cce25eSYifeng Zhao 	if (len > 4)
692d4cce25eSYifeng Zhao 		len = 4;
693d4cce25eSYifeng Zhao 
694d4cce25eSYifeng Zhao 	switch (type) {
695d4cce25eSYifeng Zhao 	case IF_TYPE_MMC:
696d4cce25eSYifeng Zhao 		media = BOOT_TYPE_EMMC;
697d4cce25eSYifeng Zhao 		break;
698d4cce25eSYifeng Zhao 
699d4cce25eSYifeng Zhao 	case IF_TYPE_SD:
700d4cce25eSYifeng Zhao 		media = BOOT_TYPE_SD0;
701d4cce25eSYifeng Zhao 		break;
702d4cce25eSYifeng Zhao 
703d4cce25eSYifeng Zhao 	case IF_TYPE_MTD:
704d4cce25eSYifeng Zhao 		if (devnum == BLK_MTD_SPI_NAND)
705d4cce25eSYifeng Zhao 			media = BOOT_TYPE_MTD_BLK_SPI_NAND;
706d4cce25eSYifeng Zhao 		else if (devnum == BLK_MTD_NAND)
707d4cce25eSYifeng Zhao 			media = BOOT_TYPE_NAND;
708d4cce25eSYifeng Zhao 		else
709d4cce25eSYifeng Zhao 			media = BOOT_TYPE_MTD_BLK_SPI_NOR;
710d4cce25eSYifeng Zhao 		break;
711d4cce25eSYifeng Zhao 
712d4cce25eSYifeng Zhao 	case IF_TYPE_SCSI:
713d4cce25eSYifeng Zhao 		media = BOOT_TYPE_SATA;
714d4cce25eSYifeng Zhao 		break;
715d4cce25eSYifeng Zhao 
716d4cce25eSYifeng Zhao 	case IF_TYPE_RKNAND:
717d4cce25eSYifeng Zhao 		media = BOOT_TYPE_NAND;
718d4cce25eSYifeng Zhao 		break;
7192daa60eeSJon Lin 
7202daa60eeSJon Lin 	case IF_TYPE_NVME:
7212daa60eeSJon Lin 		media = BOOT_TYPE_PCIE;
7222daa60eeSJon Lin 		break;
7232daa60eeSJon Lin 
724d4cce25eSYifeng Zhao 	default:
725d4cce25eSYifeng Zhao 		break;
726d4cce25eSYifeng Zhao 	}
727d4cce25eSYifeng Zhao 
728d4cce25eSYifeng Zhao 	memcpy((void *)&buf[0], (void *)&media, len);
729d4cce25eSYifeng Zhao 	common->residue = len;
730d4cce25eSYifeng Zhao 	common->data_size_from_cmnd = len;
731d4cce25eSYifeng Zhao 
732d4cce25eSYifeng Zhao 	return len;
733d4cce25eSYifeng Zhao }
734d4cce25eSYifeng Zhao 
735f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
736f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
737f16e43f8SFrank Wang {
738f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
739f16e43f8SFrank Wang 	u32 len = common->data_size;
740d015bf41SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
741e66d4537SJon Lin 	int devnum = ums[common->lun].block_dev.devnum;
742f16e43f8SFrank Wang 
743f16e43f8SFrank Wang 	/*
744f16e43f8SFrank Wang 	 * bit[0]: Direct LBA, 0: Disabled;
7450d0c3248SFrank Wang 	 * bit[1]: Vendor Storage API, 0: Disabed (default);
746d015bf41SFrank Wang 	 * bit[2]: First 4M Access, 0: Disabled;
7470d0c3248SFrank Wang 	 * bit[3]: Read LBA On, 0: Disabed (default);
7480d0c3248SFrank Wang 	 * bit[4]: New Vendor Storage API, 0: Disabed;
749d4cce25eSYifeng Zhao 	 * bit[5]: Read uart data from ram
750d4cce25eSYifeng Zhao 	 * bit[6]: Read IDB config
751d4cce25eSYifeng Zhao 	 * bit[7]: Read SecureMode
752d4cce25eSYifeng Zhao 	 * bit[8]: New IDB feature
753d4cce25eSYifeng Zhao 	 * bit[9]: Get storage media info
754d4cce25eSYifeng Zhao 	 * bit[10:63}: Reserved.
755f16e43f8SFrank Wang 	 */
756f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
7572daa60eeSJon Lin 	if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME)
7580d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(2) | BIT(4);
7590d0c3248SFrank Wang 	else
7600d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(4);
761f16e43f8SFrank Wang 
762e66d4537SJon Lin 	if (type == IF_TYPE_MTD &&
763e66d4537SJon Lin 	    (devnum == BLK_MTD_NAND ||
764e66d4537SJon Lin 	    devnum == BLK_MTD_SPI_NAND))
765e66d4537SJon Lin 		buf[0] |= (1 << 6);
766e66d4537SJon Lin 
76765a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308)
76865a0fed9SJon Lin 	if (type == IF_TYPE_MTD && devnum == BLK_MTD_SPI_NOR)
76965a0fed9SJon Lin 		buf[0] |= (1 << 6);
77065a0fed9SJon Lin #endif
77165a0fed9SJon Lin 
7720b97a2cbSJoseph Chen #if defined(CONFIG_ROCKCHIP_NEW_IDB)
773007849d8SYifeng Zhao 	buf[1] = BIT(0);
774007849d8SYifeng Zhao #endif
7752c0c66c1SYifeng Zhao 	buf[1] |= BIT(1); /* Switch Storage */
7762c0c66c1SYifeng Zhao 	buf[1] |= BIT(2); /* LBAwrite Parity */
777d4cce25eSYifeng Zhao 
778f16e43f8SFrank Wang 	/* Set data xfer size */
779e66d4537SJon Lin 	common->residue = len;
780e66d4537SJon Lin 	common->data_size_from_cmnd = len;
781f16e43f8SFrank Wang 
782f16e43f8SFrank Wang 	return len;
783f16e43f8SFrank Wang }
784f16e43f8SFrank Wang 
785d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
786d23ec8c4SKever Yang 			      struct fsg_buffhd *bh)
787d23ec8c4SKever Yang {
788d23ec8c4SKever Yang 	struct usb_request      *req = bh->outreq;
789d23ec8c4SKever Yang 	struct fsg_bulk_cb_wrap *cbw = req->buf;
790d23ec8c4SKever Yang 
791d23ec8c4SKever Yang 	/* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
792d23ec8c4SKever Yang 	common->data_size = le32_to_cpu(cbw->DataTransferLength);
793d23ec8c4SKever Yang 	if (common->data_size == 0) {
794d23ec8c4SKever Yang 		common->data_size =
795d23ec8c4SKever Yang 		get_unaligned_be16(&common->cmnd[7]) << 9;
796d23ec8c4SKever Yang 		printf("Trasfer Length NOT set, please use new version tool\n");
797d23ec8c4SKever Yang 		debug("%s %d, cmnd1 %x\n", __func__,
798d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[7]),
799d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[1]));
800d23ec8c4SKever Yang 	}
801d23ec8c4SKever Yang 	if (cbw->Flags & USB_BULK_IN_FLAG)
802d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_TO_HOST;
803d23ec8c4SKever Yang 	else
804d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_FROM_HOST;
805d23ec8c4SKever Yang 
806d23ec8c4SKever Yang 	/* Not support */
807d23ec8c4SKever Yang 	common->cmnd[1] = 0;
808d23ec8c4SKever Yang }
809d23ec8c4SKever Yang 
810f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
811f16e43f8SFrank Wang 			     struct fsg_buffhd *bh, int *reply)
812f16e43f8SFrank Wang {
813f16e43f8SFrank Wang 	struct usb_request	*req = bh->outreq;
814f16e43f8SFrank Wang 	struct fsg_bulk_cb_wrap	*cbw = req->buf;
815f16e43f8SFrank Wang 	int rc;
816f16e43f8SFrank Wang 
817f16e43f8SFrank Wang 	dump_cbw(cbw);
818f16e43f8SFrank Wang 
819f16e43f8SFrank Wang 	if (rkusb_check_lun(common)) {
820f16e43f8SFrank Wang 		*reply = -EINVAL;
821f16e43f8SFrank Wang 		return RKUSB_RC_ERROR;
822f16e43f8SFrank Wang 	}
823f16e43f8SFrank Wang 
824f16e43f8SFrank Wang 	switch (common->cmnd[0]) {
825f16e43f8SFrank Wang 	case RKUSB_TEST_UNIT_READY:
826f16e43f8SFrank Wang 		*reply = rkusb_do_test_unit_ready(common, bh);
827f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
828f16e43f8SFrank Wang 		break;
829f16e43f8SFrank Wang 
830f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_ID:
831f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_id(common, bh);
832f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
833f16e43f8SFrank Wang 		break;
834f16e43f8SFrank Wang 
835f16e43f8SFrank Wang 	case RKUSB_TEST_BAD_BLOCK:
836f16e43f8SFrank Wang 		*reply = rkusb_do_test_bad_block(common, bh);
837f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
838f16e43f8SFrank Wang 		break;
839f16e43f8SFrank Wang 
840e66d4537SJon Lin 	case RKUSB_ERASE_10_FORCE:
841e66d4537SJon Lin 		*reply = rkusb_do_erase_force(common, bh);
842e66d4537SJon Lin 		rc = RKUSB_RC_FINISHED;
843e66d4537SJon Lin 		break;
844e66d4537SJon Lin 
845f16e43f8SFrank Wang 	case RKUSB_LBA_READ_10:
8465fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
847f16e43f8SFrank Wang 		common->cmnd[0] = SC_READ_10;
848f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
849f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
850f16e43f8SFrank Wang 		break;
851f16e43f8SFrank Wang 
852f16e43f8SFrank Wang 	case RKUSB_LBA_WRITE_10:
8535fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
854f16e43f8SFrank Wang 		common->cmnd[0] = SC_WRITE_10;
855f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
856f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
857f16e43f8SFrank Wang 		break;
858f16e43f8SFrank Wang 
859f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_INFO:
860f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_info(common, bh);
861f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
862f16e43f8SFrank Wang 		break;
863f16e43f8SFrank Wang 
864829f2b85SFrank Wang 	case RKUSB_GET_CHIP_VER:
865829f2b85SFrank Wang 		*reply = rkusb_do_get_chip_info(common, bh);
866829f2b85SFrank Wang 		rc = RKUSB_RC_FINISHED;
867829f2b85SFrank Wang 		break;
868829f2b85SFrank Wang 
869f16e43f8SFrank Wang 	case RKUSB_LBA_ERASE:
870f16e43f8SFrank Wang 		*reply = rkusb_do_lba_erase(common, bh);
871f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
872f16e43f8SFrank Wang 		break;
873f16e43f8SFrank Wang 
8740d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
8750d0c3248SFrank Wang 	case RKUSB_VS_WRITE:
8760d0c3248SFrank Wang 		*reply = rkusb_do_vs_write(common);
8770d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
8780d0c3248SFrank Wang 		break;
8790d0c3248SFrank Wang 
8800d0c3248SFrank Wang 	case RKUSB_VS_READ:
8810d0c3248SFrank Wang 		*reply = rkusb_do_vs_read(common);
8820d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
8830d0c3248SFrank Wang 		break;
8840d0c3248SFrank Wang #endif
885d4cce25eSYifeng Zhao 	case RKUSB_GET_STORAGE_MEDIA:
886d4cce25eSYifeng Zhao 		*reply = rkusb_do_get_storage_info(common, bh);
887d4cce25eSYifeng Zhao 		rc = RKUSB_RC_FINISHED;
888d4cce25eSYifeng Zhao 		break;
8890d0c3248SFrank Wang 
890f16e43f8SFrank Wang 	case RKUSB_READ_CAPACITY:
891f16e43f8SFrank Wang 		*reply = rkusb_do_read_capacity(common, bh);
892f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
893f16e43f8SFrank Wang 		break;
894f16e43f8SFrank Wang 
895f16e43f8SFrank Wang 	case RKUSB_RESET:
896f16e43f8SFrank Wang 		*reply = rkusb_do_reset(common, bh);
897f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
898f16e43f8SFrank Wang 		break;
899f16e43f8SFrank Wang 
900f16e43f8SFrank Wang 	case RKUSB_READ_10:
901f16e43f8SFrank Wang 	case RKUSB_WRITE_10:
902e0023032SKever Yang 		printf("CMD Not support, pls use new version Tool\n");
903e0023032SKever Yang 	case RKUSB_SET_DEVICE_ID:
904f16e43f8SFrank Wang 	case RKUSB_ERASE_10:
905f16e43f8SFrank Wang 	case RKUSB_WRITE_SPARE:
906f16e43f8SFrank Wang 	case RKUSB_READ_SPARE:
907f16e43f8SFrank Wang 	case RKUSB_GET_VERSION:
908f16e43f8SFrank Wang 	case RKUSB_ERASE_SYS_DISK:
909f16e43f8SFrank Wang 	case RKUSB_SDRAM_READ_10:
910f16e43f8SFrank Wang 	case RKUSB_SDRAM_WRITE_10:
911f16e43f8SFrank Wang 	case RKUSB_SDRAM_EXECUTE:
912f16e43f8SFrank Wang 	case RKUSB_LOW_FORMAT:
913f16e43f8SFrank Wang 	case RKUSB_SET_RESET_FLAG:
914f16e43f8SFrank Wang 	case RKUSB_SPI_READ_10:
915f16e43f8SFrank Wang 	case RKUSB_SPI_WRITE_10:
916f16e43f8SFrank Wang 	case RKUSB_SESSION:
917f16e43f8SFrank Wang 		/* Fall through */
918f16e43f8SFrank Wang 	default:
919f16e43f8SFrank Wang 		rc = RKUSB_RC_UNKNOWN_CMND;
920f16e43f8SFrank Wang 		break;
921f16e43f8SFrank Wang 	}
922f16e43f8SFrank Wang 
923f16e43f8SFrank Wang 	return rc;
924f16e43f8SFrank Wang }
925f16e43f8SFrank Wang 
9262c0c66c1SYifeng Zhao int rkusb_do_check_parity(struct fsg_common *common)
9272c0c66c1SYifeng Zhao {
9282c0c66c1SYifeng Zhao 	int ret = 0, rc;
9292c0c66c1SYifeng Zhao 	u32 parity, i, usb_parity, lba, len;
9302c0c66c1SYifeng Zhao 	static u32 usb_check_buffer[1024 * 256];
9312c0c66c1SYifeng Zhao 
9322c0c66c1SYifeng Zhao 	usb_parity = common->cmnd[9] | (common->cmnd[10] << 8) |
9332c0c66c1SYifeng Zhao 			(common->cmnd[11] << 16) | (common->cmnd[12] << 24);
9342c0c66c1SYifeng Zhao 
9352c0c66c1SYifeng Zhao 	if (common->cmnd[0] == SC_WRITE_10 && (usb_parity)) {
9362c0c66c1SYifeng Zhao 		lba = get_unaligned_be32(&common->cmnd[2]);
9372c0c66c1SYifeng Zhao 		len = common->data_size_from_cmnd >> 9;
9382c0c66c1SYifeng Zhao 		rc = blk_dread(&ums[common->lun].block_dev, lba, len, usb_check_buffer);
9392c0c66c1SYifeng Zhao 		parity = 0x000055aa;
9402c0c66c1SYifeng Zhao 		for (i = 0; i < len * 128; i++)
9412c0c66c1SYifeng Zhao 			parity += usb_check_buffer[i];
9422c0c66c1SYifeng Zhao 		if (!rc || parity != usb_parity)
9432c0c66c1SYifeng Zhao 			common->phase_error = 1;
9442c0c66c1SYifeng Zhao 	}
9452c0c66c1SYifeng Zhao 
9462c0c66c1SYifeng Zhao 	return ret;
9472c0c66c1SYifeng Zhao }
9482c0c66c1SYifeng Zhao 
949f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
950