xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_rockusb.c (revision 19652be07ea78b9c5581d76ecf6fecd511d46eb0)
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>
9866d7966SJoseph Chen #include <asm/arch/boot_mode.h>
10829f2b85SFrank Wang #include <asm/arch/chip_info.h>
11dfbf26e8STony Xu #include <write_keybox.h>
120d0c3248SFrank Wang 
130d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
140d0c3248SFrank Wang #include <asm/arch/vendor.h>
150d0c3248SFrank Wang #endif
160d0c3248SFrank Wang 
17f16e43f8SFrank Wang #include <rockusb.h>
18f16e43f8SFrank Wang 
19f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS	0xff
20f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS	0x06
21f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL	0x05
22f16e43f8SFrank Wang 
23f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = {
24f16e43f8SFrank Wang 	.bLength		= USB_DT_INTERFACE_SIZE,
25f16e43f8SFrank Wang 	.bDescriptorType	= USB_DT_INTERFACE,
26f16e43f8SFrank Wang 	.bInterfaceNumber	= 0x00,
27f16e43f8SFrank Wang 	.bAlternateSetting	= 0x00,
28f16e43f8SFrank Wang 	.bNumEndpoints		= 0x02,
29f16e43f8SFrank Wang 	.bInterfaceClass	= ROCKUSB_INTERFACE_CLASS,
30f16e43f8SFrank Wang 	.bInterfaceSubClass	= ROCKUSB_INTERFACE_SUB_CLASS,
31f16e43f8SFrank Wang 	.bInterfaceProtocol	= ROCKUSB_INTERFACE_PROTOCOL,
32f16e43f8SFrank Wang };
33f16e43f8SFrank Wang 
34f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = {
35f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
36f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_in_desc,
37f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_out_desc,
38f16e43f8SFrank Wang 	NULL,
39f16e43f8SFrank Wang };
40f16e43f8SFrank Wang 
41f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = {
42f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
43f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_in_desc,
44f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_out_desc,
45f16e43f8SFrank Wang 	NULL,
46f16e43f8SFrank Wang };
47f16e43f8SFrank Wang 
4826dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = {
4926dd3474SWilliam Wu 	(struct usb_descriptor_header *)&rkusb_intf_desc,
5026dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_desc,
5126dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc,
5226dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_desc,
5326dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc,
5426dd3474SWilliam Wu 	NULL,
5526dd3474SWilliam Wu };
5626dd3474SWilliam Wu 
57f16e43f8SFrank Wang struct rk_flash_info {
58f16e43f8SFrank Wang 	u32	flash_size;
59f16e43f8SFrank Wang 	u16	block_size;
60f16e43f8SFrank Wang 	u8	page_size;
61f16e43f8SFrank Wang 	u8	ecc_bits;
62f16e43f8SFrank Wang 	u8	access_time;
63f16e43f8SFrank Wang 	u8	manufacturer;
64f16e43f8SFrank Wang 	u8	flash_mask;
65f16e43f8SFrank Wang } __packed;
66f16e43f8SFrank Wang 
675b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
685b081643SFrank Wang 
69f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
70f16e43f8SFrank Wang {
71ba437c8cSFrank Wang 	if (IS_RKUSB_UMS_DNL(name)) {
72c0acb0f2SFrank Wang 		/* Fix to Rockchip's VID and PID */
73ba437c8cSFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x2207);
74ba437c8cSFrank Wang 		dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
75ba437c8cSFrank Wang 
76f16e43f8SFrank Wang 		/* Enumerate as a loader device */
77f16e43f8SFrank Wang 		dev->bcdUSB = cpu_to_le16(0x0201);
78c0acb0f2SFrank Wang 	} else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
79c0acb0f2SFrank Wang 		/* Fix to Google's VID and PID */
80c0acb0f2SFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x18d1);
81c0acb0f2SFrank Wang 		dev->idProduct = __constant_cpu_to_le16(0xd00d);
82ba437c8cSFrank Wang 	}
83f16e43f8SFrank Wang 
84f16e43f8SFrank Wang 	return 0;
85f16e43f8SFrank Wang }
86f16e43f8SFrank Wang 
87f16e43f8SFrank Wang __maybe_unused
88f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
89f16e43f8SFrank Wang {
90f16e43f8SFrank Wang 	assert(!cbw);
91f16e43f8SFrank Wang 
92f16e43f8SFrank Wang 	debug("%s:\n", __func__);
93f16e43f8SFrank Wang 	debug("Signature %x\n", cbw->Signature);
94f16e43f8SFrank Wang 	debug("Tag %x\n", cbw->Tag);
95f16e43f8SFrank Wang 	debug("DataTransferLength %x\n", cbw->DataTransferLength);
96f16e43f8SFrank Wang 	debug("Flags %x\n", cbw->Flags);
97f16e43f8SFrank Wang 	debug("LUN %x\n", cbw->Lun);
98f16e43f8SFrank Wang 	debug("Length %x\n", cbw->Length);
99f16e43f8SFrank Wang 	debug("OptionCode %x\n", cbw->CDB[0]);
100f16e43f8SFrank Wang 	debug("SubCode %x\n", cbw->CDB[1]);
101f16e43f8SFrank Wang 	debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
102f16e43f8SFrank Wang 	debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
103f16e43f8SFrank Wang }
104f16e43f8SFrank Wang 
105f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
106f16e43f8SFrank Wang {
107f16e43f8SFrank Wang 	struct fsg_lun *curlun;
108f16e43f8SFrank Wang 
109f16e43f8SFrank Wang 	/* Check the LUN */
110f16e43f8SFrank Wang 	if (common->lun >= 0 && common->lun < common->nluns) {
111f16e43f8SFrank Wang 		curlun = &common->luns[common->lun];
112f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_REQUEST_SENSE) {
113f16e43f8SFrank Wang 			curlun->sense_data = SS_NO_SENSE;
114f16e43f8SFrank Wang 			curlun->info_valid = 0;
115f16e43f8SFrank Wang 		}
116f16e43f8SFrank Wang 	} else {
117f16e43f8SFrank Wang 		curlun = NULL;
118f16e43f8SFrank Wang 		common->bad_lun_okay = 0;
119f16e43f8SFrank Wang 
120f16e43f8SFrank Wang 		/*
121f16e43f8SFrank Wang 		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
122f16e43f8SFrank Wang 		 * to use unsupported LUNs; all others may not.
123f16e43f8SFrank Wang 		 */
124f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_INQUIRY &&
125f16e43f8SFrank Wang 		    common->cmnd[0] != SC_REQUEST_SENSE) {
126f16e43f8SFrank Wang 			debug("unsupported LUN %d\n", common->lun);
127f16e43f8SFrank Wang 			return -EINVAL;
128f16e43f8SFrank Wang 		}
129f16e43f8SFrank Wang 	}
130f16e43f8SFrank Wang 
131f16e43f8SFrank Wang 	return 0;
132f16e43f8SFrank Wang }
133f16e43f8SFrank Wang 
134f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
135f16e43f8SFrank Wang {
1365b081643SFrank Wang 	u32 boot_flag = BOOT_NORMAL;
1375b081643SFrank Wang 
1385b081643SFrank Wang 	if (rkusb_rst_code == 0x03)
1395b081643SFrank Wang 		boot_flag = BOOT_BROM_DOWNLOAD;
1405b081643SFrank Wang 
1415b081643SFrank Wang 	rkusb_rst_code = 0; /* restore to default */
1425b081643SFrank Wang 	writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
143866d7966SJoseph Chen 
144f16e43f8SFrank Wang 	do_reset(NULL, 0, 0, NULL);
145f16e43f8SFrank Wang }
146f16e43f8SFrank Wang 
147f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
148f16e43f8SFrank Wang 			  struct fsg_buffhd *bh)
149f16e43f8SFrank Wang {
150f16e43f8SFrank Wang 	common->data_size_from_cmnd = common->cmnd[4];
151f16e43f8SFrank Wang 	common->residue = 0;
152f16e43f8SFrank Wang 	bh->inreq->complete = __do_reset;
153f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
154f16e43f8SFrank Wang 
1555b081643SFrank Wang 	rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
156f16e43f8SFrank Wang 	return 0;
157f16e43f8SFrank Wang }
158f16e43f8SFrank Wang 
159f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
160f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
161f16e43f8SFrank Wang {
162f16e43f8SFrank Wang 	common->residue = 0x06 << 24; /* Max block xfer support from host */
163f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
164f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
165f16e43f8SFrank Wang 
166f16e43f8SFrank Wang 	return 0;
167f16e43f8SFrank Wang }
168f16e43f8SFrank Wang 
169f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
170f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
171f16e43f8SFrank Wang {
172f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
173e0023032SKever Yang 	u32 len = 5;
174d7386f60SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
175f16e43f8SFrank Wang 
176d7386f60SFrank Wang 	if (type == IF_TYPE_MMC)
177f16e43f8SFrank Wang 		memcpy((void *)&buf[0], "EMMC ", 5);
178d7386f60SFrank Wang 	else if (type == IF_TYPE_RKNAND)
179d7386f60SFrank Wang 		memcpy((void *)&buf[0], "NAND ", 5);
180d7386f60SFrank Wang 	else
181d7386f60SFrank Wang 		memcpy((void *)&buf[0], "UNKN ", 5); /* unknown */
182f16e43f8SFrank Wang 
183f16e43f8SFrank Wang 	/* Set data xfer size */
184f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
185e0023032SKever Yang 	common->data_size = len;
186f16e43f8SFrank Wang 
187f16e43f8SFrank Wang 	return len;
188f16e43f8SFrank Wang }
189f16e43f8SFrank Wang 
190f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
191f16e43f8SFrank Wang 				   struct fsg_buffhd *bh)
192f16e43f8SFrank Wang {
193f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
194e0023032SKever Yang 	u32 len = 64;
195f16e43f8SFrank Wang 
196f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
197f16e43f8SFrank Wang 
198f16e43f8SFrank Wang 	/* Set data xfer size */
199f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
200e0023032SKever Yang 	common->data_size = len;
201f16e43f8SFrank Wang 
202f16e43f8SFrank Wang 	return len;
203f16e43f8SFrank Wang }
204f16e43f8SFrank Wang 
205f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
206f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
207f16e43f8SFrank Wang {
208f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
209d23ec8c4SKever Yang 	u32 len = sizeof(struct rk_flash_info);
210f16e43f8SFrank Wang 	struct rk_flash_info finfo = {
211f16e43f8SFrank Wang 		.block_size = 1024,
212f16e43f8SFrank Wang 		.ecc_bits = 0,
213f16e43f8SFrank Wang 		.page_size = 4,
214f16e43f8SFrank Wang 		.access_time = 40,
215f16e43f8SFrank Wang 		.manufacturer = 0,
216f16e43f8SFrank Wang 		.flash_mask = 0
217f16e43f8SFrank Wang 	};
218f16e43f8SFrank Wang 
219f16e43f8SFrank Wang 	finfo.flash_size = (u32)ums[common->lun].block_dev.lba;
220f16e43f8SFrank Wang 	if (finfo.flash_size)
221f16e43f8SFrank Wang 		finfo.flash_mask = 1;
222f16e43f8SFrank Wang 
223f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
224f16e43f8SFrank Wang 	memcpy((void *)&buf[0], (void *)&finfo, len);
225f16e43f8SFrank Wang 
226f16e43f8SFrank Wang 	/* Set data xfer size */
227f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
228d23ec8c4SKever Yang         /* legacy upgrade_tool does not set correct transfer size */
229d23ec8c4SKever Yang 	common->data_size = len;
230f16e43f8SFrank Wang 
231f16e43f8SFrank Wang 	return len;
232f16e43f8SFrank Wang }
233f16e43f8SFrank Wang 
234829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
235829f2b85SFrank Wang 				  struct fsg_buffhd *bh)
236829f2b85SFrank Wang {
237829f2b85SFrank Wang 	u8 *buf = (u8 *)bh->buf;
238829f2b85SFrank Wang 	u32 len = common->data_size;
239829f2b85SFrank Wang 	u32 chip_info[4];
240829f2b85SFrank Wang 
241829f2b85SFrank Wang 	memset((void *)chip_info, 0, sizeof(chip_info));
242829f2b85SFrank Wang 	rockchip_rockusb_get_chip_info(chip_info);
243829f2b85SFrank Wang 
244829f2b85SFrank Wang 	memset((void *)&buf[0], 0, len);
245829f2b85SFrank Wang 	memcpy((void *)&buf[0], (void *)chip_info, len);
246829f2b85SFrank Wang 
247829f2b85SFrank Wang 	/* Set data xfer size */
248829f2b85SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
249829f2b85SFrank Wang 
250829f2b85SFrank Wang 	return len;
251829f2b85SFrank Wang }
252829f2b85SFrank Wang 
253f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
254f16e43f8SFrank Wang 			      struct fsg_buffhd *bh)
255f16e43f8SFrank Wang {
256f16e43f8SFrank Wang 	struct fsg_lun *curlun = &common->luns[common->lun];
257f16e43f8SFrank Wang 	u32 lba, amount;
258f16e43f8SFrank Wang 	loff_t file_offset;
259f16e43f8SFrank Wang 	int rc;
260f16e43f8SFrank Wang 
261f16e43f8SFrank Wang 	lba = get_unaligned_be32(&common->cmnd[2]);
262f16e43f8SFrank Wang 	if (lba >= curlun->num_sectors) {
263f16e43f8SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
264f16e43f8SFrank Wang 		rc = -EINVAL;
265f16e43f8SFrank Wang 		goto out;
266f16e43f8SFrank Wang 	}
267f16e43f8SFrank Wang 
268f16e43f8SFrank Wang 	file_offset = ((loff_t) lba) << 9;
269f16e43f8SFrank Wang 	amount = get_unaligned_be16(&common->cmnd[7]) << 9;
270f16e43f8SFrank Wang 	if (unlikely(amount == 0)) {
271f16e43f8SFrank Wang 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
272f16e43f8SFrank Wang 		rc = -EIO;
273f16e43f8SFrank Wang 		goto out;
274f16e43f8SFrank Wang 	}
275f16e43f8SFrank Wang 
276f16e43f8SFrank Wang 	/* Perform the erase */
277f16e43f8SFrank Wang 	rc = ums[common->lun].erase_sector(&ums[common->lun],
278f16e43f8SFrank Wang 			       file_offset / SECTOR_SIZE,
279f16e43f8SFrank Wang 			       amount / SECTOR_SIZE);
280f16e43f8SFrank Wang 	if (!rc) {
281f16e43f8SFrank Wang 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
282f16e43f8SFrank Wang 		rc = -EIO;
283f16e43f8SFrank Wang 	}
284f16e43f8SFrank Wang 
285f16e43f8SFrank Wang out:
286f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
287f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
288f16e43f8SFrank Wang 
289f16e43f8SFrank Wang 	return rc;
290f16e43f8SFrank Wang }
291f16e43f8SFrank Wang 
2920d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
2930d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
2940d0c3248SFrank Wang {
2950d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
2960d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
2970d0c3248SFrank Wang 	struct vendor_item	*vhead;
2980d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
2990d0c3248SFrank Wang 	void			*data;
3000d0c3248SFrank Wang 	int			rc;
3010d0c3248SFrank Wang 
3020d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
3030d0c3248SFrank Wang 		/* _MUST_ small than 64K */
3040d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
3050d0c3248SFrank Wang 		return -EINVAL;
3060d0c3248SFrank Wang 	}
3070d0c3248SFrank Wang 
3080d0c3248SFrank Wang 	common->residue         = common->data_size;
3090d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
3100d0c3248SFrank Wang 
3110d0c3248SFrank Wang 	/* Carry out the file writes */
3120d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
3130d0c3248SFrank Wang 		return -EIO; /* No data to write */
3140d0c3248SFrank Wang 
3150d0c3248SFrank Wang 	for (;;) {
3160d0c3248SFrank Wang 		if (common->usb_amount_left > 0) {
3170d0c3248SFrank Wang 			/* Wait for the next buffer to become available */
3180d0c3248SFrank Wang 			bh = common->next_buffhd_to_fill;
3190d0c3248SFrank Wang 			if (bh->state != BUF_STATE_EMPTY)
3200d0c3248SFrank Wang 				goto wait;
3210d0c3248SFrank Wang 
3220d0c3248SFrank Wang 			/* Request the next buffer */
3230d0c3248SFrank Wang 			common->usb_amount_left      -= common->data_size;
3240d0c3248SFrank Wang 			bh->outreq->length	     = common->data_size;
3250d0c3248SFrank Wang 			bh->bulk_out_intended_length = common->data_size;
3260d0c3248SFrank Wang 			bh->outreq->short_not_ok     = 1;
3270d0c3248SFrank Wang 
3280d0c3248SFrank Wang 			START_TRANSFER_OR(common, bulk_out, bh->outreq,
3290d0c3248SFrank Wang 					  &bh->outreq_busy, &bh->state)
3300d0c3248SFrank Wang 				/*
3310d0c3248SFrank Wang 				 * Don't know what to do if
3320d0c3248SFrank Wang 				 * common->fsg is NULL
3330d0c3248SFrank Wang 				 */
3340d0c3248SFrank Wang 				return -EIO;
3350d0c3248SFrank Wang 			common->next_buffhd_to_fill = bh->next;
3360d0c3248SFrank Wang 		} else {
3370d0c3248SFrank Wang 			/* Then, wait for the data to become available */
3380d0c3248SFrank Wang 			bh = common->next_buffhd_to_drain;
3390d0c3248SFrank Wang 			if (bh->state != BUF_STATE_FULL)
3400d0c3248SFrank Wang 				goto wait;
3410d0c3248SFrank Wang 
3420d0c3248SFrank Wang 			common->next_buffhd_to_drain = bh->next;
3430d0c3248SFrank Wang 			bh->state = BUF_STATE_EMPTY;
3440d0c3248SFrank Wang 
3450d0c3248SFrank Wang 			/* Did something go wrong with the transfer? */
3460d0c3248SFrank Wang 			if (bh->outreq->status != 0) {
3470d0c3248SFrank Wang 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
3480d0c3248SFrank Wang 				curlun->info_valid = 1;
3490d0c3248SFrank Wang 				break;
3500d0c3248SFrank Wang 			}
3510d0c3248SFrank Wang 
3520d0c3248SFrank Wang 			/* Perform the write */
3530d0c3248SFrank Wang 			vhead = (struct vendor_item *)bh->buf;
3540d0c3248SFrank Wang 			data  = bh->buf + sizeof(struct vendor_item);
3550d0c3248SFrank Wang 
3560d0c3248SFrank Wang 			if (!type) {
3570d0c3248SFrank Wang 				/* Vendor storage */
3580d0c3248SFrank Wang 				rc = vendor_storage_write(vhead->id,
3590d0c3248SFrank Wang 							  (char __user *)data,
3600d0c3248SFrank Wang 							  vhead->size);
361*19652be0SFrank Wang 				if (rc < 0) {
362*19652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
3630d0c3248SFrank Wang 					return -EIO;
364*19652be0SFrank Wang 				}
3650d0c3248SFrank Wang 			} else {
3660d0c3248SFrank Wang 				/* RPMB */
3676f0347c8Stony.xu 				rc =
3686f0347c8Stony.xu 				write_keybox_to_secure_storage((u8 *)data,
3696f0347c8Stony.xu 							       vhead->size);
370*19652be0SFrank Wang 				if (rc < 0) {
371*19652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
3726f0347c8Stony.xu 					return -EIO;
3730d0c3248SFrank Wang 				}
374*19652be0SFrank Wang 			}
3750d0c3248SFrank Wang 
3760d0c3248SFrank Wang 			common->residue -= common->data_size;
3770d0c3248SFrank Wang 
3780d0c3248SFrank Wang 			/* Did the host decide to stop early? */
3790d0c3248SFrank Wang 			if (bh->outreq->actual != bh->outreq->length)
3800d0c3248SFrank Wang 				common->short_packet_received = 1;
3810d0c3248SFrank Wang 			break; /* Command done */
3820d0c3248SFrank Wang 		}
3830d0c3248SFrank Wang wait:
3840d0c3248SFrank Wang 		/* Wait for something to happen */
3850d0c3248SFrank Wang 		rc = sleep_thread(common);
3860d0c3248SFrank Wang 		if (rc)
3870d0c3248SFrank Wang 			return rc;
3880d0c3248SFrank Wang 	}
3890d0c3248SFrank Wang 
3900d0c3248SFrank Wang 	return -EIO; /* No default reply */
3910d0c3248SFrank Wang }
3920d0c3248SFrank Wang 
3930d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
3940d0c3248SFrank Wang {
3950d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
3960d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
3970d0c3248SFrank Wang 	struct vendor_item	*vhead;
3980d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
3990d0c3248SFrank Wang 	void			*data;
4000d0c3248SFrank Wang 	int			rc;
4010d0c3248SFrank Wang 
4020d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
4030d0c3248SFrank Wang 		/* _MUST_ small than 64K */
4040d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
4050d0c3248SFrank Wang 		return -EINVAL;
4060d0c3248SFrank Wang 	}
4070d0c3248SFrank Wang 
4080d0c3248SFrank Wang 	common->residue         = common->data_size;
4090d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
4100d0c3248SFrank Wang 
4110d0c3248SFrank Wang 	/* Carry out the file reads */
4120d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
4130d0c3248SFrank Wang 		return -EIO; /* No default reply */
4140d0c3248SFrank Wang 
4150d0c3248SFrank Wang 	for (;;) {
4160d0c3248SFrank Wang 		/* Wait for the next buffer to become available */
4170d0c3248SFrank Wang 		bh = common->next_buffhd_to_fill;
4180d0c3248SFrank Wang 		while (bh->state != BUF_STATE_EMPTY) {
4190d0c3248SFrank Wang 			rc = sleep_thread(common);
4200d0c3248SFrank Wang 			if (rc)
4210d0c3248SFrank Wang 				return rc;
4220d0c3248SFrank Wang 		}
4230d0c3248SFrank Wang 
4240d0c3248SFrank Wang 		memset(bh->buf, 0, FSG_BUFLEN);
4250d0c3248SFrank Wang 		vhead = (struct vendor_item *)bh->buf;
4260d0c3248SFrank Wang 		data  = bh->buf + sizeof(struct vendor_item);
4270d0c3248SFrank Wang 		vhead->id = get_unaligned_be16(&common->cmnd[2]);
4280d0c3248SFrank Wang 
4290d0c3248SFrank Wang 		if (!type) {
4300d0c3248SFrank Wang 			/* Vendor storage */
4310d0c3248SFrank Wang 			rc = vendor_storage_read(vhead->id,
4320d0c3248SFrank Wang 						 (char __user *)data,
4330d0c3248SFrank Wang 						 common->data_size);
434*19652be0SFrank Wang 			if (!rc) {
435*19652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
4360d0c3248SFrank Wang 				return -EIO;
437*19652be0SFrank Wang 			}
4380d0c3248SFrank Wang 			vhead->size = rc;
4390d0c3248SFrank Wang 		} else {
4400d0c3248SFrank Wang 			/* RPMB */
441700a3668STony Xu 			rc =
442700a3668STony Xu 			read_raw_data_from_secure_storage((u8 *)data,
443700a3668STony Xu 							  common->data_size);
444*19652be0SFrank Wang 			if (!rc) {
445*19652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
446700a3668STony Xu 				return -EIO;
447*19652be0SFrank Wang 			}
448700a3668STony Xu 			vhead->size = rc;
4490d0c3248SFrank Wang 		}
4500d0c3248SFrank Wang 
4510d0c3248SFrank Wang 		common->residue   -= common->data_size;
4520d0c3248SFrank Wang 		bh->inreq->length = common->data_size;
4530d0c3248SFrank Wang 		bh->state         = BUF_STATE_FULL;
4540d0c3248SFrank Wang 
4550d0c3248SFrank Wang 		break; /* No more left to read */
4560d0c3248SFrank Wang 	}
4570d0c3248SFrank Wang 
4580d0c3248SFrank Wang 	return -EIO; /* No default reply */
4590d0c3248SFrank Wang }
4600d0c3248SFrank Wang #endif
4610d0c3248SFrank Wang 
462f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
463f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
464f16e43f8SFrank Wang {
465f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
466f16e43f8SFrank Wang 	u32 len = common->data_size;
467d015bf41SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
468f16e43f8SFrank Wang 
469f16e43f8SFrank Wang 	/*
470f16e43f8SFrank Wang 	 * bit[0]: Direct LBA, 0: Disabled;
4710d0c3248SFrank Wang 	 * bit[1]: Vendor Storage API, 0: Disabed (default);
472d015bf41SFrank Wang 	 * bit[2]: First 4M Access, 0: Disabled;
4730d0c3248SFrank Wang 	 * bit[3]: Read LBA On, 0: Disabed (default);
4740d0c3248SFrank Wang 	 * bit[4]: New Vendor Storage API, 0: Disabed;
4750d0c3248SFrank Wang 	 * bit[5:63}: Reserved.
476f16e43f8SFrank Wang 	 */
477f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
478af5a2012SJason Zhu 	if (type == IF_TYPE_MMC || type == IF_TYPE_SD)
4790d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(2) | BIT(4);
4800d0c3248SFrank Wang 	else
4810d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(4);
482f16e43f8SFrank Wang 
483f16e43f8SFrank Wang 	/* Set data xfer size */
484f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
485f16e43f8SFrank Wang 
486f16e43f8SFrank Wang 	return len;
487f16e43f8SFrank Wang }
488f16e43f8SFrank Wang 
489d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
490d23ec8c4SKever Yang 			      struct fsg_buffhd *bh)
491d23ec8c4SKever Yang {
492d23ec8c4SKever Yang 	struct usb_request      *req = bh->outreq;
493d23ec8c4SKever Yang 	struct fsg_bulk_cb_wrap *cbw = req->buf;
494d23ec8c4SKever Yang 
495d23ec8c4SKever Yang 	/* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
496d23ec8c4SKever Yang 	common->data_size = le32_to_cpu(cbw->DataTransferLength);
497d23ec8c4SKever Yang 	if (common->data_size == 0) {
498d23ec8c4SKever Yang 		common->data_size =
499d23ec8c4SKever Yang 		get_unaligned_be16(&common->cmnd[7]) << 9;
500d23ec8c4SKever Yang 		printf("Trasfer Length NOT set, please use new version tool\n");
501d23ec8c4SKever Yang 		debug("%s %d, cmnd1 %x\n", __func__,
502d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[7]),
503d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[1]));
504d23ec8c4SKever Yang 	}
505d23ec8c4SKever Yang 	if (cbw->Flags & USB_BULK_IN_FLAG)
506d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_TO_HOST;
507d23ec8c4SKever Yang 	else
508d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_FROM_HOST;
509d23ec8c4SKever Yang 
510d23ec8c4SKever Yang 	/* Not support */
511d23ec8c4SKever Yang 	common->cmnd[1] = 0;
512d23ec8c4SKever Yang }
513d23ec8c4SKever Yang 
514f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
515f16e43f8SFrank Wang 			     struct fsg_buffhd *bh, int *reply)
516f16e43f8SFrank Wang {
517f16e43f8SFrank Wang 	struct usb_request	*req = bh->outreq;
518f16e43f8SFrank Wang 	struct fsg_bulk_cb_wrap	*cbw = req->buf;
519f16e43f8SFrank Wang 	int rc;
520f16e43f8SFrank Wang 
521f16e43f8SFrank Wang 	dump_cbw(cbw);
522f16e43f8SFrank Wang 
523f16e43f8SFrank Wang 	if (rkusb_check_lun(common)) {
524f16e43f8SFrank Wang 		*reply = -EINVAL;
525f16e43f8SFrank Wang 		return RKUSB_RC_ERROR;
526f16e43f8SFrank Wang 	}
527f16e43f8SFrank Wang 
528f16e43f8SFrank Wang 	switch (common->cmnd[0]) {
529f16e43f8SFrank Wang 	case RKUSB_TEST_UNIT_READY:
530f16e43f8SFrank Wang 		*reply = rkusb_do_test_unit_ready(common, bh);
531f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
532f16e43f8SFrank Wang 		break;
533f16e43f8SFrank Wang 
534f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_ID:
535f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_id(common, bh);
536f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
537f16e43f8SFrank Wang 		break;
538f16e43f8SFrank Wang 
539f16e43f8SFrank Wang 	case RKUSB_TEST_BAD_BLOCK:
540f16e43f8SFrank Wang 		*reply = rkusb_do_test_bad_block(common, bh);
541f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
542f16e43f8SFrank Wang 		break;
543f16e43f8SFrank Wang 
544f16e43f8SFrank Wang 	case RKUSB_LBA_READ_10:
5455fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
546f16e43f8SFrank Wang 		common->cmnd[0] = SC_READ_10;
547f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
548f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
549f16e43f8SFrank Wang 		break;
550f16e43f8SFrank Wang 
551f16e43f8SFrank Wang 	case RKUSB_LBA_WRITE_10:
5525fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
553f16e43f8SFrank Wang 		common->cmnd[0] = SC_WRITE_10;
554f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
555f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
556f16e43f8SFrank Wang 		break;
557f16e43f8SFrank Wang 
558f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_INFO:
559f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_info(common, bh);
560f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
561f16e43f8SFrank Wang 		break;
562f16e43f8SFrank Wang 
563829f2b85SFrank Wang 	case RKUSB_GET_CHIP_VER:
564829f2b85SFrank Wang 		*reply = rkusb_do_get_chip_info(common, bh);
565829f2b85SFrank Wang 		rc = RKUSB_RC_FINISHED;
566829f2b85SFrank Wang 		break;
567829f2b85SFrank Wang 
568f16e43f8SFrank Wang 	case RKUSB_LBA_ERASE:
569f16e43f8SFrank Wang 		*reply = rkusb_do_lba_erase(common, bh);
570f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
571f16e43f8SFrank Wang 		break;
572f16e43f8SFrank Wang 
5730d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
5740d0c3248SFrank Wang 	case RKUSB_VS_WRITE:
5750d0c3248SFrank Wang 		*reply = rkusb_do_vs_write(common);
5760d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
5770d0c3248SFrank Wang 		break;
5780d0c3248SFrank Wang 
5790d0c3248SFrank Wang 	case RKUSB_VS_READ:
5800d0c3248SFrank Wang 		*reply = rkusb_do_vs_read(common);
5810d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
5820d0c3248SFrank Wang 		break;
5830d0c3248SFrank Wang #endif
5840d0c3248SFrank Wang 
585f16e43f8SFrank Wang 	case RKUSB_READ_CAPACITY:
586f16e43f8SFrank Wang 		*reply = rkusb_do_read_capacity(common, bh);
587f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
588f16e43f8SFrank Wang 		break;
589f16e43f8SFrank Wang 
590f16e43f8SFrank Wang 	case RKUSB_RESET:
591f16e43f8SFrank Wang 		*reply = rkusb_do_reset(common, bh);
592f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
593f16e43f8SFrank Wang 		break;
594f16e43f8SFrank Wang 
595f16e43f8SFrank Wang 	case RKUSB_READ_10:
596f16e43f8SFrank Wang 	case RKUSB_WRITE_10:
597e0023032SKever Yang 		printf("CMD Not support, pls use new version Tool\n");
598e0023032SKever Yang 	case RKUSB_SET_DEVICE_ID:
599f16e43f8SFrank Wang 	case RKUSB_ERASE_10:
600f16e43f8SFrank Wang 	case RKUSB_WRITE_SPARE:
601f16e43f8SFrank Wang 	case RKUSB_READ_SPARE:
602f16e43f8SFrank Wang 	case RKUSB_ERASE_10_FORCE:
603f16e43f8SFrank Wang 	case RKUSB_GET_VERSION:
604f16e43f8SFrank Wang 	case RKUSB_ERASE_SYS_DISK:
605f16e43f8SFrank Wang 	case RKUSB_SDRAM_READ_10:
606f16e43f8SFrank Wang 	case RKUSB_SDRAM_WRITE_10:
607f16e43f8SFrank Wang 	case RKUSB_SDRAM_EXECUTE:
608f16e43f8SFrank Wang 	case RKUSB_LOW_FORMAT:
609f16e43f8SFrank Wang 	case RKUSB_SET_RESET_FLAG:
610f16e43f8SFrank Wang 	case RKUSB_SPI_READ_10:
611f16e43f8SFrank Wang 	case RKUSB_SPI_WRITE_10:
612f16e43f8SFrank Wang 	case RKUSB_SESSION:
613f16e43f8SFrank Wang 		/* Fall through */
614f16e43f8SFrank Wang 	default:
615f16e43f8SFrank Wang 		rc = RKUSB_RC_UNKNOWN_CMND;
616f16e43f8SFrank Wang 		break;
617f16e43f8SFrank Wang 	}
618f16e43f8SFrank Wang 
619f16e43f8SFrank Wang 	return rc;
620f16e43f8SFrank Wang }
621f16e43f8SFrank Wang 
622f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
623