xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_rockusb.c (revision f18b06fb49ee7a4d1fbc876e72d427ee23b0c31b)
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>
116f0347c8Stony.xu #include <optee_include/OpteeClientInterface.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 
48f16e43f8SFrank Wang struct rk_flash_info {
49f16e43f8SFrank Wang 	u32	flash_size;
50f16e43f8SFrank Wang 	u16	block_size;
51f16e43f8SFrank Wang 	u8	page_size;
52f16e43f8SFrank Wang 	u8	ecc_bits;
53f16e43f8SFrank Wang 	u8	access_time;
54f16e43f8SFrank Wang 	u8	manufacturer;
55f16e43f8SFrank Wang 	u8	flash_mask;
56f16e43f8SFrank Wang } __packed;
57f16e43f8SFrank Wang 
585b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
595b081643SFrank Wang 
60f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
61f16e43f8SFrank Wang {
62ba437c8cSFrank Wang 	if (IS_RKUSB_UMS_DNL(name)) {
63c0acb0f2SFrank Wang 		/* Fix to Rockchip's VID and PID */
64ba437c8cSFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x2207);
65ba437c8cSFrank Wang 		dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
66ba437c8cSFrank Wang 
67f16e43f8SFrank Wang 		/* Enumerate as a loader device */
68f16e43f8SFrank Wang 		dev->bcdUSB = cpu_to_le16(0x0201);
69c0acb0f2SFrank Wang 	} else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
70c0acb0f2SFrank Wang 		/* Fix to Google's VID and PID */
71c0acb0f2SFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x18d1);
72c0acb0f2SFrank Wang 		dev->idProduct = __constant_cpu_to_le16(0xd00d);
73ba437c8cSFrank Wang 	}
74f16e43f8SFrank Wang 
75f16e43f8SFrank Wang 	return 0;
76f16e43f8SFrank Wang }
77f16e43f8SFrank Wang 
78f16e43f8SFrank Wang __maybe_unused
79f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
80f16e43f8SFrank Wang {
81f16e43f8SFrank Wang 	assert(!cbw);
82f16e43f8SFrank Wang 
83f16e43f8SFrank Wang 	debug("%s:\n", __func__);
84f16e43f8SFrank Wang 	debug("Signature %x\n", cbw->Signature);
85f16e43f8SFrank Wang 	debug("Tag %x\n", cbw->Tag);
86f16e43f8SFrank Wang 	debug("DataTransferLength %x\n", cbw->DataTransferLength);
87f16e43f8SFrank Wang 	debug("Flags %x\n", cbw->Flags);
88f16e43f8SFrank Wang 	debug("LUN %x\n", cbw->Lun);
89f16e43f8SFrank Wang 	debug("Length %x\n", cbw->Length);
90f16e43f8SFrank Wang 	debug("OptionCode %x\n", cbw->CDB[0]);
91f16e43f8SFrank Wang 	debug("SubCode %x\n", cbw->CDB[1]);
92f16e43f8SFrank Wang 	debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
93f16e43f8SFrank Wang 	debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
94f16e43f8SFrank Wang }
95f16e43f8SFrank Wang 
96f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
97f16e43f8SFrank Wang {
98f16e43f8SFrank Wang 	struct fsg_lun *curlun;
99f16e43f8SFrank Wang 
100f16e43f8SFrank Wang 	/* Check the LUN */
101f16e43f8SFrank Wang 	if (common->lun >= 0 && common->lun < common->nluns) {
102f16e43f8SFrank Wang 		curlun = &common->luns[common->lun];
103f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_REQUEST_SENSE) {
104f16e43f8SFrank Wang 			curlun->sense_data = SS_NO_SENSE;
105f16e43f8SFrank Wang 			curlun->info_valid = 0;
106f16e43f8SFrank Wang 		}
107f16e43f8SFrank Wang 	} else {
108f16e43f8SFrank Wang 		curlun = NULL;
109f16e43f8SFrank Wang 		common->bad_lun_okay = 0;
110f16e43f8SFrank Wang 
111f16e43f8SFrank Wang 		/*
112f16e43f8SFrank Wang 		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
113f16e43f8SFrank Wang 		 * to use unsupported LUNs; all others may not.
114f16e43f8SFrank Wang 		 */
115f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_INQUIRY &&
116f16e43f8SFrank Wang 		    common->cmnd[0] != SC_REQUEST_SENSE) {
117f16e43f8SFrank Wang 			debug("unsupported LUN %d\n", common->lun);
118f16e43f8SFrank Wang 			return -EINVAL;
119f16e43f8SFrank Wang 		}
120f16e43f8SFrank Wang 	}
121f16e43f8SFrank Wang 
122f16e43f8SFrank Wang 	return 0;
123f16e43f8SFrank Wang }
124f16e43f8SFrank Wang 
125f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
126f16e43f8SFrank Wang {
1275b081643SFrank Wang 	u32 boot_flag = BOOT_NORMAL;
1285b081643SFrank Wang 
1295b081643SFrank Wang 	if (rkusb_rst_code == 0x03)
1305b081643SFrank Wang 		boot_flag = BOOT_BROM_DOWNLOAD;
1315b081643SFrank Wang 
1325b081643SFrank Wang 	rkusb_rst_code = 0; /* restore to default */
1335b081643SFrank Wang 	writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
134866d7966SJoseph Chen 
135f16e43f8SFrank Wang 	do_reset(NULL, 0, 0, NULL);
136f16e43f8SFrank Wang }
137f16e43f8SFrank Wang 
138f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
139f16e43f8SFrank Wang 			  struct fsg_buffhd *bh)
140f16e43f8SFrank Wang {
141f16e43f8SFrank Wang 	common->data_size_from_cmnd = common->cmnd[4];
142f16e43f8SFrank Wang 	common->residue = 0;
143f16e43f8SFrank Wang 	bh->inreq->complete = __do_reset;
144f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
145f16e43f8SFrank Wang 
1465b081643SFrank Wang 	rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
147f16e43f8SFrank Wang 	return 0;
148f16e43f8SFrank Wang }
149f16e43f8SFrank Wang 
150f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
151f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
152f16e43f8SFrank Wang {
153f16e43f8SFrank Wang 	common->residue = 0x06 << 24; /* Max block xfer support from host */
154f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
155f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
156f16e43f8SFrank Wang 
157f16e43f8SFrank Wang 	return 0;
158f16e43f8SFrank Wang }
159f16e43f8SFrank Wang 
160f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
161f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
162f16e43f8SFrank Wang {
163f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
164e0023032SKever Yang 	u32 len = 5;
165d7386f60SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
166f16e43f8SFrank Wang 
167d7386f60SFrank Wang 	if (type == IF_TYPE_MMC)
168f16e43f8SFrank Wang 		memcpy((void *)&buf[0], "EMMC ", 5);
169d7386f60SFrank Wang 	else if (type == IF_TYPE_RKNAND)
170d7386f60SFrank Wang 		memcpy((void *)&buf[0], "NAND ", 5);
171d7386f60SFrank Wang 	else
172d7386f60SFrank Wang 		memcpy((void *)&buf[0], "UNKN ", 5); /* unknown */
173f16e43f8SFrank Wang 
174f16e43f8SFrank Wang 	/* Set data xfer size */
175f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
176e0023032SKever Yang 	common->data_size = len;
177f16e43f8SFrank Wang 
178f16e43f8SFrank Wang 	return len;
179f16e43f8SFrank Wang }
180f16e43f8SFrank Wang 
181f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
182f16e43f8SFrank Wang 				   struct fsg_buffhd *bh)
183f16e43f8SFrank Wang {
184f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
185e0023032SKever Yang 	u32 len = 64;
186f16e43f8SFrank Wang 
187f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
188f16e43f8SFrank Wang 
189f16e43f8SFrank Wang 	/* Set data xfer size */
190f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
191e0023032SKever Yang 	common->data_size = len;
192f16e43f8SFrank Wang 
193f16e43f8SFrank Wang 	return len;
194f16e43f8SFrank Wang }
195f16e43f8SFrank Wang 
196f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
197f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
198f16e43f8SFrank Wang {
199f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
200d23ec8c4SKever Yang 	u32 len = sizeof(struct rk_flash_info);
201f16e43f8SFrank Wang 	struct rk_flash_info finfo = {
202f16e43f8SFrank Wang 		.block_size = 1024,
203f16e43f8SFrank Wang 		.ecc_bits = 0,
204f16e43f8SFrank Wang 		.page_size = 4,
205f16e43f8SFrank Wang 		.access_time = 40,
206f16e43f8SFrank Wang 		.manufacturer = 0,
207f16e43f8SFrank Wang 		.flash_mask = 0
208f16e43f8SFrank Wang 	};
209f16e43f8SFrank Wang 
210f16e43f8SFrank Wang 	finfo.flash_size = (u32)ums[common->lun].block_dev.lba;
211f16e43f8SFrank Wang 	if (finfo.flash_size)
212f16e43f8SFrank Wang 		finfo.flash_mask = 1;
213f16e43f8SFrank Wang 
214f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
215f16e43f8SFrank Wang 	memcpy((void *)&buf[0], (void *)&finfo, len);
216f16e43f8SFrank Wang 
217f16e43f8SFrank Wang 	/* Set data xfer size */
218f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
219d23ec8c4SKever Yang         /* legacy upgrade_tool does not set correct transfer size */
220d23ec8c4SKever Yang 	common->data_size = len;
221f16e43f8SFrank Wang 
222f16e43f8SFrank Wang 	return len;
223f16e43f8SFrank Wang }
224f16e43f8SFrank Wang 
225829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
226829f2b85SFrank Wang 				  struct fsg_buffhd *bh)
227829f2b85SFrank Wang {
228829f2b85SFrank Wang 	u8 *buf = (u8 *)bh->buf;
229829f2b85SFrank Wang 	u32 len = common->data_size;
230829f2b85SFrank Wang 	u32 chip_info[4];
231829f2b85SFrank Wang 
232829f2b85SFrank Wang 	memset((void *)chip_info, 0, sizeof(chip_info));
233829f2b85SFrank Wang 	rockchip_rockusb_get_chip_info(chip_info);
234829f2b85SFrank Wang 
235829f2b85SFrank Wang 	memset((void *)&buf[0], 0, len);
236829f2b85SFrank Wang 	memcpy((void *)&buf[0], (void *)chip_info, len);
237829f2b85SFrank Wang 
238829f2b85SFrank Wang 	/* Set data xfer size */
239829f2b85SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
240829f2b85SFrank Wang 
241829f2b85SFrank Wang 	return len;
242829f2b85SFrank Wang }
243829f2b85SFrank Wang 
244f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
245f16e43f8SFrank Wang 			      struct fsg_buffhd *bh)
246f16e43f8SFrank Wang {
247f16e43f8SFrank Wang 	struct fsg_lun *curlun = &common->luns[common->lun];
248f16e43f8SFrank Wang 	u32 lba, amount;
249f16e43f8SFrank Wang 	loff_t file_offset;
250f16e43f8SFrank Wang 	int rc;
251f16e43f8SFrank Wang 
252f16e43f8SFrank Wang 	lba = get_unaligned_be32(&common->cmnd[2]);
253f16e43f8SFrank Wang 	if (lba >= curlun->num_sectors) {
254f16e43f8SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
255f16e43f8SFrank Wang 		rc = -EINVAL;
256f16e43f8SFrank Wang 		goto out;
257f16e43f8SFrank Wang 	}
258f16e43f8SFrank Wang 
259f16e43f8SFrank Wang 	file_offset = ((loff_t) lba) << 9;
260f16e43f8SFrank Wang 	amount = get_unaligned_be16(&common->cmnd[7]) << 9;
261f16e43f8SFrank Wang 	if (unlikely(amount == 0)) {
262f16e43f8SFrank Wang 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
263f16e43f8SFrank Wang 		rc = -EIO;
264f16e43f8SFrank Wang 		goto out;
265f16e43f8SFrank Wang 	}
266f16e43f8SFrank Wang 
267f16e43f8SFrank Wang 	/* Perform the erase */
268f16e43f8SFrank Wang 	rc = ums[common->lun].erase_sector(&ums[common->lun],
269f16e43f8SFrank Wang 			       file_offset / SECTOR_SIZE,
270f16e43f8SFrank Wang 			       amount / SECTOR_SIZE);
271f16e43f8SFrank Wang 	if (!rc) {
272f16e43f8SFrank Wang 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
273f16e43f8SFrank Wang 		rc = -EIO;
274f16e43f8SFrank Wang 	}
275f16e43f8SFrank Wang 
276f16e43f8SFrank Wang out:
277f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
278f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
279f16e43f8SFrank Wang 
280f16e43f8SFrank Wang 	return rc;
281f16e43f8SFrank Wang }
282f16e43f8SFrank Wang 
2830d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
2840d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
2850d0c3248SFrank Wang {
2860d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
2870d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
2880d0c3248SFrank Wang 	struct vendor_item	*vhead;
2890d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
2900d0c3248SFrank Wang 	void			*data;
2910d0c3248SFrank Wang 	int			rc;
2920d0c3248SFrank Wang 
2930d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
2940d0c3248SFrank Wang 		/* _MUST_ small than 64K */
2950d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
2960d0c3248SFrank Wang 		return -EINVAL;
2970d0c3248SFrank Wang 	}
2980d0c3248SFrank Wang 
2990d0c3248SFrank Wang 	common->residue         = common->data_size;
3000d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
3010d0c3248SFrank Wang 
3020d0c3248SFrank Wang 	/* Carry out the file writes */
3030d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
3040d0c3248SFrank Wang 		return -EIO; /* No data to write */
3050d0c3248SFrank Wang 
3060d0c3248SFrank Wang 	for (;;) {
3070d0c3248SFrank Wang 		if (common->usb_amount_left > 0) {
3080d0c3248SFrank Wang 			/* Wait for the next buffer to become available */
3090d0c3248SFrank Wang 			bh = common->next_buffhd_to_fill;
3100d0c3248SFrank Wang 			if (bh->state != BUF_STATE_EMPTY)
3110d0c3248SFrank Wang 				goto wait;
3120d0c3248SFrank Wang 
3130d0c3248SFrank Wang 			/* Request the next buffer */
3140d0c3248SFrank Wang 			common->usb_amount_left      -= common->data_size;
3150d0c3248SFrank Wang 			bh->outreq->length	     = common->data_size;
3160d0c3248SFrank Wang 			bh->bulk_out_intended_length = common->data_size;
3170d0c3248SFrank Wang 			bh->outreq->short_not_ok     = 1;
3180d0c3248SFrank Wang 
3190d0c3248SFrank Wang 			START_TRANSFER_OR(common, bulk_out, bh->outreq,
3200d0c3248SFrank Wang 					  &bh->outreq_busy, &bh->state)
3210d0c3248SFrank Wang 				/*
3220d0c3248SFrank Wang 				 * Don't know what to do if
3230d0c3248SFrank Wang 				 * common->fsg is NULL
3240d0c3248SFrank Wang 				 */
3250d0c3248SFrank Wang 				return -EIO;
3260d0c3248SFrank Wang 			common->next_buffhd_to_fill = bh->next;
3270d0c3248SFrank Wang 		} else {
3280d0c3248SFrank Wang 			/* Then, wait for the data to become available */
3290d0c3248SFrank Wang 			bh = common->next_buffhd_to_drain;
3300d0c3248SFrank Wang 			if (bh->state != BUF_STATE_FULL)
3310d0c3248SFrank Wang 				goto wait;
3320d0c3248SFrank Wang 
3330d0c3248SFrank Wang 			common->next_buffhd_to_drain = bh->next;
3340d0c3248SFrank Wang 			bh->state = BUF_STATE_EMPTY;
3350d0c3248SFrank Wang 
3360d0c3248SFrank Wang 			/* Did something go wrong with the transfer? */
3370d0c3248SFrank Wang 			if (bh->outreq->status != 0) {
3380d0c3248SFrank Wang 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
3390d0c3248SFrank Wang 				curlun->info_valid = 1;
3400d0c3248SFrank Wang 				break;
3410d0c3248SFrank Wang 			}
3420d0c3248SFrank Wang 
3430d0c3248SFrank Wang 			/* Perform the write */
3440d0c3248SFrank Wang 			vhead = (struct vendor_item *)bh->buf;
3450d0c3248SFrank Wang 			data  = bh->buf + sizeof(struct vendor_item);
3460d0c3248SFrank Wang 
3470d0c3248SFrank Wang 			if (!type) {
3480d0c3248SFrank Wang 				/* Vendor storage */
3490d0c3248SFrank Wang 				rc = vendor_storage_write(vhead->id,
3500d0c3248SFrank Wang 							  (char __user *)data,
3510d0c3248SFrank Wang 							  vhead->size);
3520d0c3248SFrank Wang 				if (rc < 0)
3530d0c3248SFrank Wang 					return -EIO;
3540d0c3248SFrank Wang 			} else {
3550d0c3248SFrank Wang 				/* RPMB */
3566f0347c8Stony.xu #ifdef CONFIG_OPTEE_V1
3576f0347c8Stony.xu 				rc =
3586f0347c8Stony.xu 				write_keybox_to_secure_storage((u8 *)data,
3596f0347c8Stony.xu 							       vhead->size);
360*f18b06fbSTony Xu 				if (rc < 0)
3616f0347c8Stony.xu 					return -EIO;
3626f0347c8Stony.xu #endif
3630d0c3248SFrank Wang 			}
3640d0c3248SFrank Wang 
3650d0c3248SFrank Wang 			common->residue -= common->data_size;
3660d0c3248SFrank Wang 
3670d0c3248SFrank Wang 			/* Did the host decide to stop early? */
3680d0c3248SFrank Wang 			if (bh->outreq->actual != bh->outreq->length)
3690d0c3248SFrank Wang 				common->short_packet_received = 1;
3700d0c3248SFrank Wang 			break; /* Command done */
3710d0c3248SFrank Wang 		}
3720d0c3248SFrank Wang wait:
3730d0c3248SFrank Wang 		/* Wait for something to happen */
3740d0c3248SFrank Wang 		rc = sleep_thread(common);
3750d0c3248SFrank Wang 		if (rc)
3760d0c3248SFrank Wang 			return rc;
3770d0c3248SFrank Wang 	}
3780d0c3248SFrank Wang 
3790d0c3248SFrank Wang 	return -EIO; /* No default reply */
3800d0c3248SFrank Wang }
3810d0c3248SFrank Wang 
3820d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
3830d0c3248SFrank Wang {
3840d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
3850d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
3860d0c3248SFrank Wang 	struct vendor_item	*vhead;
3870d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
3880d0c3248SFrank Wang 	void			*data;
3890d0c3248SFrank Wang 	int			rc;
3900d0c3248SFrank Wang 
3910d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
3920d0c3248SFrank Wang 		/* _MUST_ small than 64K */
3930d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
3940d0c3248SFrank Wang 		return -EINVAL;
3950d0c3248SFrank Wang 	}
3960d0c3248SFrank Wang 
3970d0c3248SFrank Wang 	common->residue         = common->data_size;
3980d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
3990d0c3248SFrank Wang 
4000d0c3248SFrank Wang 	/* Carry out the file reads */
4010d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
4020d0c3248SFrank Wang 		return -EIO; /* No default reply */
4030d0c3248SFrank Wang 
4040d0c3248SFrank Wang 	for (;;) {
4050d0c3248SFrank Wang 		/* Wait for the next buffer to become available */
4060d0c3248SFrank Wang 		bh = common->next_buffhd_to_fill;
4070d0c3248SFrank Wang 		while (bh->state != BUF_STATE_EMPTY) {
4080d0c3248SFrank Wang 			rc = sleep_thread(common);
4090d0c3248SFrank Wang 			if (rc)
4100d0c3248SFrank Wang 				return rc;
4110d0c3248SFrank Wang 		}
4120d0c3248SFrank Wang 
4130d0c3248SFrank Wang 		memset(bh->buf, 0, FSG_BUFLEN);
4140d0c3248SFrank Wang 		vhead = (struct vendor_item *)bh->buf;
4150d0c3248SFrank Wang 		data  = bh->buf + sizeof(struct vendor_item);
4160d0c3248SFrank Wang 		vhead->id = get_unaligned_be16(&common->cmnd[2]);
4170d0c3248SFrank Wang 
4180d0c3248SFrank Wang 		if (!type) {
4190d0c3248SFrank Wang 			/* Vendor storage */
4200d0c3248SFrank Wang 			rc = vendor_storage_read(vhead->id,
4210d0c3248SFrank Wang 						 (char __user *)data,
4220d0c3248SFrank Wang 						 common->data_size);
4230d0c3248SFrank Wang 			if (!rc)
4240d0c3248SFrank Wang 				return -EIO;
4250d0c3248SFrank Wang 			vhead->size = rc;
4260d0c3248SFrank Wang 		} else {
4270d0c3248SFrank Wang 			/* RPMB */
4280d0c3248SFrank Wang 		}
4290d0c3248SFrank Wang 
4300d0c3248SFrank Wang 		common->residue   -= common->data_size;
4310d0c3248SFrank Wang 		bh->inreq->length = common->data_size;
4320d0c3248SFrank Wang 		bh->state         = BUF_STATE_FULL;
4330d0c3248SFrank Wang 
4340d0c3248SFrank Wang 		break; /* No more left to read */
4350d0c3248SFrank Wang 	}
4360d0c3248SFrank Wang 
4370d0c3248SFrank Wang 	return -EIO; /* No default reply */
4380d0c3248SFrank Wang }
4390d0c3248SFrank Wang #endif
4400d0c3248SFrank Wang 
441f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
442f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
443f16e43f8SFrank Wang {
444f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
445f16e43f8SFrank Wang 	u32 len = common->data_size;
446d015bf41SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
447f16e43f8SFrank Wang 
448f16e43f8SFrank Wang 	/*
449f16e43f8SFrank Wang 	 * bit[0]: Direct LBA, 0: Disabled;
4500d0c3248SFrank Wang 	 * bit[1]: Vendor Storage API, 0: Disabed (default);
451d015bf41SFrank Wang 	 * bit[2]: First 4M Access, 0: Disabled;
4520d0c3248SFrank Wang 	 * bit[3]: Read LBA On, 0: Disabed (default);
4530d0c3248SFrank Wang 	 * bit[4]: New Vendor Storage API, 0: Disabed;
4540d0c3248SFrank Wang 	 * bit[5:63}: Reserved.
455f16e43f8SFrank Wang 	 */
456f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
4570d0c3248SFrank Wang 	if (type == IF_TYPE_MMC)
4580d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(2) | BIT(4);
4590d0c3248SFrank Wang 	else
4600d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(4);
461f16e43f8SFrank Wang 
462f16e43f8SFrank Wang 	/* Set data xfer size */
463f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
464f16e43f8SFrank Wang 
465f16e43f8SFrank Wang 	return len;
466f16e43f8SFrank Wang }
467f16e43f8SFrank Wang 
468d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
469d23ec8c4SKever Yang 			      struct fsg_buffhd *bh)
470d23ec8c4SKever Yang {
471d23ec8c4SKever Yang 	struct usb_request      *req = bh->outreq;
472d23ec8c4SKever Yang 	struct fsg_bulk_cb_wrap *cbw = req->buf;
473d23ec8c4SKever Yang 
474d23ec8c4SKever Yang 	/* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
475d23ec8c4SKever Yang 	common->data_size = le32_to_cpu(cbw->DataTransferLength);
476d23ec8c4SKever Yang 	if (common->data_size == 0) {
477d23ec8c4SKever Yang 		common->data_size =
478d23ec8c4SKever Yang 		get_unaligned_be16(&common->cmnd[7]) << 9;
479d23ec8c4SKever Yang 		printf("Trasfer Length NOT set, please use new version tool\n");
480d23ec8c4SKever Yang 		debug("%s %d, cmnd1 %x\n", __func__,
481d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[7]),
482d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[1]));
483d23ec8c4SKever Yang 	}
484d23ec8c4SKever Yang 	if (cbw->Flags & USB_BULK_IN_FLAG)
485d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_TO_HOST;
486d23ec8c4SKever Yang 	else
487d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_FROM_HOST;
488d23ec8c4SKever Yang 
489d23ec8c4SKever Yang 	/* Not support */
490d23ec8c4SKever Yang 	common->cmnd[1] = 0;
491d23ec8c4SKever Yang }
492d23ec8c4SKever Yang 
493f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
494f16e43f8SFrank Wang 			     struct fsg_buffhd *bh, int *reply)
495f16e43f8SFrank Wang {
496f16e43f8SFrank Wang 	struct usb_request	*req = bh->outreq;
497f16e43f8SFrank Wang 	struct fsg_bulk_cb_wrap	*cbw = req->buf;
498f16e43f8SFrank Wang 	int rc;
499f16e43f8SFrank Wang 
500f16e43f8SFrank Wang 	dump_cbw(cbw);
501f16e43f8SFrank Wang 
502f16e43f8SFrank Wang 	if (rkusb_check_lun(common)) {
503f16e43f8SFrank Wang 		*reply = -EINVAL;
504f16e43f8SFrank Wang 		return RKUSB_RC_ERROR;
505f16e43f8SFrank Wang 	}
506f16e43f8SFrank Wang 
507f16e43f8SFrank Wang 	switch (common->cmnd[0]) {
508f16e43f8SFrank Wang 	case RKUSB_TEST_UNIT_READY:
509f16e43f8SFrank Wang 		*reply = rkusb_do_test_unit_ready(common, bh);
510f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
511f16e43f8SFrank Wang 		break;
512f16e43f8SFrank Wang 
513f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_ID:
514f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_id(common, bh);
515f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
516f16e43f8SFrank Wang 		break;
517f16e43f8SFrank Wang 
518f16e43f8SFrank Wang 	case RKUSB_TEST_BAD_BLOCK:
519f16e43f8SFrank Wang 		*reply = rkusb_do_test_bad_block(common, bh);
520f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
521f16e43f8SFrank Wang 		break;
522f16e43f8SFrank Wang 
523f16e43f8SFrank Wang 	case RKUSB_LBA_READ_10:
5245fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
525f16e43f8SFrank Wang 		common->cmnd[0] = SC_READ_10;
526f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
527f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
528f16e43f8SFrank Wang 		break;
529f16e43f8SFrank Wang 
530f16e43f8SFrank Wang 	case RKUSB_LBA_WRITE_10:
5315fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
532f16e43f8SFrank Wang 		common->cmnd[0] = SC_WRITE_10;
533f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
534f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
535f16e43f8SFrank Wang 		break;
536f16e43f8SFrank Wang 
537f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_INFO:
538f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_info(common, bh);
539f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
540f16e43f8SFrank Wang 		break;
541f16e43f8SFrank Wang 
542829f2b85SFrank Wang 	case RKUSB_GET_CHIP_VER:
543829f2b85SFrank Wang 		*reply = rkusb_do_get_chip_info(common, bh);
544829f2b85SFrank Wang 		rc = RKUSB_RC_FINISHED;
545829f2b85SFrank Wang 		break;
546829f2b85SFrank Wang 
547f16e43f8SFrank Wang 	case RKUSB_LBA_ERASE:
548f16e43f8SFrank Wang 		*reply = rkusb_do_lba_erase(common, bh);
549f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
550f16e43f8SFrank Wang 		break;
551f16e43f8SFrank Wang 
5520d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
5530d0c3248SFrank Wang 	case RKUSB_VS_WRITE:
5540d0c3248SFrank Wang 		*reply = rkusb_do_vs_write(common);
5550d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
5560d0c3248SFrank Wang 		break;
5570d0c3248SFrank Wang 
5580d0c3248SFrank Wang 	case RKUSB_VS_READ:
5590d0c3248SFrank Wang 		*reply = rkusb_do_vs_read(common);
5600d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
5610d0c3248SFrank Wang 		break;
5620d0c3248SFrank Wang #endif
5630d0c3248SFrank Wang 
564f16e43f8SFrank Wang 	case RKUSB_READ_CAPACITY:
565f16e43f8SFrank Wang 		*reply = rkusb_do_read_capacity(common, bh);
566f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
567f16e43f8SFrank Wang 		break;
568f16e43f8SFrank Wang 
569f16e43f8SFrank Wang 	case RKUSB_RESET:
570f16e43f8SFrank Wang 		*reply = rkusb_do_reset(common, bh);
571f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
572f16e43f8SFrank Wang 		break;
573f16e43f8SFrank Wang 
574f16e43f8SFrank Wang 	case RKUSB_READ_10:
575f16e43f8SFrank Wang 	case RKUSB_WRITE_10:
576e0023032SKever Yang 		printf("CMD Not support, pls use new version Tool\n");
577e0023032SKever Yang 	case RKUSB_SET_DEVICE_ID:
578f16e43f8SFrank Wang 	case RKUSB_ERASE_10:
579f16e43f8SFrank Wang 	case RKUSB_WRITE_SPARE:
580f16e43f8SFrank Wang 	case RKUSB_READ_SPARE:
581f16e43f8SFrank Wang 	case RKUSB_ERASE_10_FORCE:
582f16e43f8SFrank Wang 	case RKUSB_GET_VERSION:
583f16e43f8SFrank Wang 	case RKUSB_ERASE_SYS_DISK:
584f16e43f8SFrank Wang 	case RKUSB_SDRAM_READ_10:
585f16e43f8SFrank Wang 	case RKUSB_SDRAM_WRITE_10:
586f16e43f8SFrank Wang 	case RKUSB_SDRAM_EXECUTE:
587f16e43f8SFrank Wang 	case RKUSB_LOW_FORMAT:
588f16e43f8SFrank Wang 	case RKUSB_SET_RESET_FLAG:
589f16e43f8SFrank Wang 	case RKUSB_SPI_READ_10:
590f16e43f8SFrank Wang 	case RKUSB_SPI_WRITE_10:
591f16e43f8SFrank Wang 	case RKUSB_SESSION:
592f16e43f8SFrank Wang 		/* Fall through */
593f16e43f8SFrank Wang 	default:
594f16e43f8SFrank Wang 		rc = RKUSB_RC_UNKNOWN_CMND;
595f16e43f8SFrank Wang 		break;
596f16e43f8SFrank Wang 	}
597f16e43f8SFrank Wang 
598f16e43f8SFrank Wang 	return rc;
599f16e43f8SFrank Wang }
600f16e43f8SFrank Wang 
601f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
602