xref: /rk3399_rockchip-uboot/drivers/usb/gadget/f_rockusb.c (revision e66d4537dbd86d2c766c7745e41d41fd88ae2b83)
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>
12*e66d4537SJon Lin #include <linux/mtd/mtd.h>
130d0c3248SFrank Wang 
140d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
150d0c3248SFrank Wang #include <asm/arch/vendor.h>
160d0c3248SFrank Wang #endif
170d0c3248SFrank Wang 
18f16e43f8SFrank Wang #include <rockusb.h>
19f16e43f8SFrank Wang 
20f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS	0xff
21f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS	0x06
22f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL	0x05
23f16e43f8SFrank Wang 
24*e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE	1024
25*e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE	4
26*e66d4537SJon Lin 
27f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = {
28f16e43f8SFrank Wang 	.bLength		= USB_DT_INTERFACE_SIZE,
29f16e43f8SFrank Wang 	.bDescriptorType	= USB_DT_INTERFACE,
30f16e43f8SFrank Wang 	.bInterfaceNumber	= 0x00,
31f16e43f8SFrank Wang 	.bAlternateSetting	= 0x00,
32f16e43f8SFrank Wang 	.bNumEndpoints		= 0x02,
33f16e43f8SFrank Wang 	.bInterfaceClass	= ROCKUSB_INTERFACE_CLASS,
34f16e43f8SFrank Wang 	.bInterfaceSubClass	= ROCKUSB_INTERFACE_SUB_CLASS,
35f16e43f8SFrank Wang 	.bInterfaceProtocol	= ROCKUSB_INTERFACE_PROTOCOL,
36f16e43f8SFrank Wang };
37f16e43f8SFrank Wang 
38f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = {
39f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
40f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_in_desc,
41f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_fs_bulk_out_desc,
42f16e43f8SFrank Wang 	NULL,
43f16e43f8SFrank Wang };
44f16e43f8SFrank Wang 
45f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = {
46f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&rkusb_intf_desc,
47f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_in_desc,
48f16e43f8SFrank Wang 	(struct usb_descriptor_header *)&fsg_hs_bulk_out_desc,
49f16e43f8SFrank Wang 	NULL,
50f16e43f8SFrank Wang };
51f16e43f8SFrank Wang 
5226dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = {
5326dd3474SWilliam Wu 	(struct usb_descriptor_header *)&rkusb_intf_desc,
5426dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_desc,
5526dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc,
5626dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_desc,
5726dd3474SWilliam Wu 	(struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc,
5826dd3474SWilliam Wu 	NULL,
5926dd3474SWilliam Wu };
6026dd3474SWilliam Wu 
61f16e43f8SFrank Wang struct rk_flash_info {
62f16e43f8SFrank Wang 	u32	flash_size;
63f16e43f8SFrank Wang 	u16	block_size;
64f16e43f8SFrank Wang 	u8	page_size;
65f16e43f8SFrank Wang 	u8	ecc_bits;
66f16e43f8SFrank Wang 	u8	access_time;
67f16e43f8SFrank Wang 	u8	manufacturer;
68f16e43f8SFrank Wang 	u8	flash_mask;
69f16e43f8SFrank Wang } __packed;
70f16e43f8SFrank Wang 
715b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
725b081643SFrank Wang 
73f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
74f16e43f8SFrank Wang {
75ba437c8cSFrank Wang 	if (IS_RKUSB_UMS_DNL(name)) {
76c0acb0f2SFrank Wang 		/* Fix to Rockchip's VID and PID */
77ba437c8cSFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x2207);
78ba437c8cSFrank Wang 		dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
79ba437c8cSFrank Wang 
80f16e43f8SFrank Wang 		/* Enumerate as a loader device */
8195424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG)
8295424692SJoseph Chen 		dev->bcdUSB = cpu_to_le16(0x0200);
8395424692SJoseph Chen #else
84f16e43f8SFrank Wang 		dev->bcdUSB = cpu_to_le16(0x0201);
8595424692SJoseph Chen #endif
86c0acb0f2SFrank Wang 	} else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
87c0acb0f2SFrank Wang 		/* Fix to Google's VID and PID */
88c0acb0f2SFrank Wang 		dev->idVendor  = __constant_cpu_to_le16(0x18d1);
89c0acb0f2SFrank Wang 		dev->idProduct = __constant_cpu_to_le16(0xd00d);
90ba437c8cSFrank Wang 	}
91f16e43f8SFrank Wang 
92f16e43f8SFrank Wang 	return 0;
93f16e43f8SFrank Wang }
94f16e43f8SFrank Wang 
95f16e43f8SFrank Wang __maybe_unused
96f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
97f16e43f8SFrank Wang {
98f16e43f8SFrank Wang 	assert(!cbw);
99f16e43f8SFrank Wang 
100f16e43f8SFrank Wang 	debug("%s:\n", __func__);
101f16e43f8SFrank Wang 	debug("Signature %x\n", cbw->Signature);
102f16e43f8SFrank Wang 	debug("Tag %x\n", cbw->Tag);
103f16e43f8SFrank Wang 	debug("DataTransferLength %x\n", cbw->DataTransferLength);
104f16e43f8SFrank Wang 	debug("Flags %x\n", cbw->Flags);
105f16e43f8SFrank Wang 	debug("LUN %x\n", cbw->Lun);
106f16e43f8SFrank Wang 	debug("Length %x\n", cbw->Length);
107f16e43f8SFrank Wang 	debug("OptionCode %x\n", cbw->CDB[0]);
108f16e43f8SFrank Wang 	debug("SubCode %x\n", cbw->CDB[1]);
109f16e43f8SFrank Wang 	debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
110f16e43f8SFrank Wang 	debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
111f16e43f8SFrank Wang }
112f16e43f8SFrank Wang 
113f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
114f16e43f8SFrank Wang {
115f16e43f8SFrank Wang 	struct fsg_lun *curlun;
116f16e43f8SFrank Wang 
117f16e43f8SFrank Wang 	/* Check the LUN */
118f16e43f8SFrank Wang 	if (common->lun >= 0 && common->lun < common->nluns) {
119f16e43f8SFrank Wang 		curlun = &common->luns[common->lun];
120f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_REQUEST_SENSE) {
121f16e43f8SFrank Wang 			curlun->sense_data = SS_NO_SENSE;
122f16e43f8SFrank Wang 			curlun->info_valid = 0;
123f16e43f8SFrank Wang 		}
124f16e43f8SFrank Wang 	} else {
125f16e43f8SFrank Wang 		curlun = NULL;
126f16e43f8SFrank Wang 		common->bad_lun_okay = 0;
127f16e43f8SFrank Wang 
128f16e43f8SFrank Wang 		/*
129f16e43f8SFrank Wang 		 * INQUIRY and REQUEST SENSE commands are explicitly allowed
130f16e43f8SFrank Wang 		 * to use unsupported LUNs; all others may not.
131f16e43f8SFrank Wang 		 */
132f16e43f8SFrank Wang 		if (common->cmnd[0] != SC_INQUIRY &&
133f16e43f8SFrank Wang 		    common->cmnd[0] != SC_REQUEST_SENSE) {
134f16e43f8SFrank Wang 			debug("unsupported LUN %d\n", common->lun);
135f16e43f8SFrank Wang 			return -EINVAL;
136f16e43f8SFrank Wang 		}
137f16e43f8SFrank Wang 	}
138f16e43f8SFrank Wang 
139f16e43f8SFrank Wang 	return 0;
140f16e43f8SFrank Wang }
141f16e43f8SFrank Wang 
142f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
143f16e43f8SFrank Wang {
1445b081643SFrank Wang 	u32 boot_flag = BOOT_NORMAL;
1455b081643SFrank Wang 
1465b081643SFrank Wang 	if (rkusb_rst_code == 0x03)
1475b081643SFrank Wang 		boot_flag = BOOT_BROM_DOWNLOAD;
1485b081643SFrank Wang 
1495b081643SFrank Wang 	rkusb_rst_code = 0; /* restore to default */
1505b081643SFrank Wang 	writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
151866d7966SJoseph Chen 
152f16e43f8SFrank Wang 	do_reset(NULL, 0, 0, NULL);
153f16e43f8SFrank Wang }
154f16e43f8SFrank Wang 
155f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
156f16e43f8SFrank Wang 			  struct fsg_buffhd *bh)
157f16e43f8SFrank Wang {
158f16e43f8SFrank Wang 	common->data_size_from_cmnd = common->cmnd[4];
159f16e43f8SFrank Wang 	common->residue = 0;
160f16e43f8SFrank Wang 	bh->inreq->complete = __do_reset;
161f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
162f16e43f8SFrank Wang 
1635b081643SFrank Wang 	rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
164f16e43f8SFrank Wang 	return 0;
165f16e43f8SFrank Wang }
166f16e43f8SFrank Wang 
167f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
168f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
169f16e43f8SFrank Wang {
170f16e43f8SFrank Wang 	common->residue = 0x06 << 24; /* Max block xfer support from host */
171f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
172f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
173f16e43f8SFrank Wang 
174f16e43f8SFrank Wang 	return 0;
175f16e43f8SFrank Wang }
176f16e43f8SFrank Wang 
177f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
178f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
179f16e43f8SFrank Wang {
180f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
181e0023032SKever Yang 	u32 len = 5;
182d7386f60SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
183f16e43f8SFrank Wang 
184d7386f60SFrank Wang 	if (type == IF_TYPE_MMC)
185f16e43f8SFrank Wang 		memcpy((void *)&buf[0], "EMMC ", 5);
186d7386f60SFrank Wang 	else if (type == IF_TYPE_RKNAND)
187d7386f60SFrank Wang 		memcpy((void *)&buf[0], "NAND ", 5);
188d7386f60SFrank Wang 	else
189d7386f60SFrank Wang 		memcpy((void *)&buf[0], "UNKN ", 5); /* unknown */
190f16e43f8SFrank Wang 
191f16e43f8SFrank Wang 	/* Set data xfer size */
192f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
193e0023032SKever Yang 	common->data_size = len;
194f16e43f8SFrank Wang 
195f16e43f8SFrank Wang 	return len;
196f16e43f8SFrank Wang }
197f16e43f8SFrank Wang 
198f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
199f16e43f8SFrank Wang 				   struct fsg_buffhd *bh)
200f16e43f8SFrank Wang {
201f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
202e0023032SKever Yang 	u32 len = 64;
203f16e43f8SFrank Wang 
204f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
205f16e43f8SFrank Wang 
206f16e43f8SFrank Wang 	/* Set data xfer size */
207f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
208e0023032SKever Yang 	common->data_size = len;
209f16e43f8SFrank Wang 
210f16e43f8SFrank Wang 	return len;
211f16e43f8SFrank Wang }
212f16e43f8SFrank Wang 
213f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
214f16e43f8SFrank Wang 				    struct fsg_buffhd *bh)
215f16e43f8SFrank Wang {
216*e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
217f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
218d23ec8c4SKever Yang 	u32 len = sizeof(struct rk_flash_info);
219f16e43f8SFrank Wang 	struct rk_flash_info finfo = {
220*e66d4537SJon Lin 		.block_size = ROCKCHIP_FLASH_BLOCK_SIZE,
221f16e43f8SFrank Wang 		.ecc_bits = 0,
222*e66d4537SJon Lin 		.page_size = ROCKCHIP_FLASH_PAGE_SIZE,
223f16e43f8SFrank Wang 		.access_time = 40,
224f16e43f8SFrank Wang 		.manufacturer = 0,
225f16e43f8SFrank Wang 		.flash_mask = 0
226f16e43f8SFrank Wang 	};
227f16e43f8SFrank Wang 
228*e66d4537SJon Lin 	finfo.flash_size = (u32)desc->lba;
229*e66d4537SJon Lin 
230*e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
231*e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
232*e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
233*e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
234*e66d4537SJon Lin 
235*e66d4537SJon Lin 		if (mtd) {
236*e66d4537SJon Lin 			finfo.block_size = mtd->erasesize >> 9;
237*e66d4537SJon Lin 			finfo.page_size = mtd->writesize >> 9;
238*e66d4537SJon Lin 		}
239*e66d4537SJon Lin 	}
240*e66d4537SJon Lin 
241*e66d4537SJon Lin 	debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size,
242*e66d4537SJon Lin 	      finfo.page_size);
243*e66d4537SJon Lin 
244f16e43f8SFrank Wang 	if (finfo.flash_size)
245f16e43f8SFrank Wang 		finfo.flash_mask = 1;
246f16e43f8SFrank Wang 
247f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
248f16e43f8SFrank Wang 	memcpy((void *)&buf[0], (void *)&finfo, len);
249f16e43f8SFrank Wang 
250f16e43f8SFrank Wang 	/* Set data xfer size */
251f16e43f8SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
252d23ec8c4SKever Yang         /* legacy upgrade_tool does not set correct transfer size */
253d23ec8c4SKever Yang 	common->data_size = len;
254f16e43f8SFrank Wang 
255f16e43f8SFrank Wang 	return len;
256f16e43f8SFrank Wang }
257f16e43f8SFrank Wang 
258829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
259829f2b85SFrank Wang 				  struct fsg_buffhd *bh)
260829f2b85SFrank Wang {
261829f2b85SFrank Wang 	u8 *buf = (u8 *)bh->buf;
262829f2b85SFrank Wang 	u32 len = common->data_size;
263829f2b85SFrank Wang 	u32 chip_info[4];
264829f2b85SFrank Wang 
265829f2b85SFrank Wang 	memset((void *)chip_info, 0, sizeof(chip_info));
266829f2b85SFrank Wang 	rockchip_rockusb_get_chip_info(chip_info);
267829f2b85SFrank Wang 
268829f2b85SFrank Wang 	memset((void *)&buf[0], 0, len);
269829f2b85SFrank Wang 	memcpy((void *)&buf[0], (void *)chip_info, len);
270829f2b85SFrank Wang 
271829f2b85SFrank Wang 	/* Set data xfer size */
272829f2b85SFrank Wang 	common->residue = common->data_size_from_cmnd = len;
273829f2b85SFrank Wang 
274829f2b85SFrank Wang 	return len;
275829f2b85SFrank Wang }
276829f2b85SFrank Wang 
277f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
278f16e43f8SFrank Wang 			      struct fsg_buffhd *bh)
279f16e43f8SFrank Wang {
280f16e43f8SFrank Wang 	struct fsg_lun *curlun = &common->luns[common->lun];
281f16e43f8SFrank Wang 	u32 lba, amount;
282f16e43f8SFrank Wang 	loff_t file_offset;
283f16e43f8SFrank Wang 	int rc;
284f16e43f8SFrank Wang 
285f16e43f8SFrank Wang 	lba = get_unaligned_be32(&common->cmnd[2]);
286f16e43f8SFrank Wang 	if (lba >= curlun->num_sectors) {
287f16e43f8SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
288f16e43f8SFrank Wang 		rc = -EINVAL;
289f16e43f8SFrank Wang 		goto out;
290f16e43f8SFrank Wang 	}
291f16e43f8SFrank Wang 
292f16e43f8SFrank Wang 	file_offset = ((loff_t) lba) << 9;
293f16e43f8SFrank Wang 	amount = get_unaligned_be16(&common->cmnd[7]) << 9;
294f16e43f8SFrank Wang 	if (unlikely(amount == 0)) {
295f16e43f8SFrank Wang 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
296f16e43f8SFrank Wang 		rc = -EIO;
297f16e43f8SFrank Wang 		goto out;
298f16e43f8SFrank Wang 	}
299f16e43f8SFrank Wang 
300f16e43f8SFrank Wang 	/* Perform the erase */
301f16e43f8SFrank Wang 	rc = ums[common->lun].erase_sector(&ums[common->lun],
302f16e43f8SFrank Wang 			       file_offset / SECTOR_SIZE,
303f16e43f8SFrank Wang 			       amount / SECTOR_SIZE);
304f16e43f8SFrank Wang 	if (!rc) {
305f16e43f8SFrank Wang 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
306f16e43f8SFrank Wang 		rc = -EIO;
307f16e43f8SFrank Wang 	}
308f16e43f8SFrank Wang 
309f16e43f8SFrank Wang out:
310f16e43f8SFrank Wang 	common->data_dir = DATA_DIR_NONE;
311f16e43f8SFrank Wang 	bh->state = BUF_STATE_EMPTY;
312f16e43f8SFrank Wang 
313f16e43f8SFrank Wang 	return rc;
314f16e43f8SFrank Wang }
315f16e43f8SFrank Wang 
316*e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common,
317*e66d4537SJon Lin 				struct fsg_buffhd *bh)
318*e66d4537SJon Lin {
319*e66d4537SJon Lin 	struct blk_desc *desc = &ums[common->lun].block_dev;
320*e66d4537SJon Lin 	struct fsg_lun *curlun = &common->luns[common->lun];
321*e66d4537SJon Lin 	u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
322*e66d4537SJon Lin 	u32 lba, amount;
323*e66d4537SJon Lin 	loff_t file_offset;
324*e66d4537SJon Lin 	int rc;
325*e66d4537SJon Lin 
326*e66d4537SJon Lin 	lba = get_unaligned_be32(&common->cmnd[2]);
327*e66d4537SJon Lin 	if (lba >= curlun->num_sectors) {
328*e66d4537SJon Lin 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
329*e66d4537SJon Lin 		rc = -EINVAL;
330*e66d4537SJon Lin 		goto out;
331*e66d4537SJon Lin 	}
332*e66d4537SJon Lin 
333*e66d4537SJon Lin 	if (desc->if_type == IF_TYPE_MTD &&
334*e66d4537SJon Lin 	    (desc->devnum == BLK_MTD_NAND ||
335*e66d4537SJon Lin 	    desc->devnum == BLK_MTD_SPI_NAND)) {
336*e66d4537SJon Lin 		struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
337*e66d4537SJon Lin 
338*e66d4537SJon Lin 		if (mtd)
339*e66d4537SJon Lin 			block_size = mtd->erasesize >> 9;
340*e66d4537SJon Lin 	}
341*e66d4537SJon Lin 
342*e66d4537SJon Lin 	file_offset = ((loff_t)lba) * block_size;
343*e66d4537SJon Lin 	amount = get_unaligned_be16(&common->cmnd[7]) * block_size;
344*e66d4537SJon Lin 
345*e66d4537SJon Lin 	debug("%s lba= %x, nsec= %x\n", __func__, lba,
346*e66d4537SJon Lin 	      (u32)get_unaligned_be16(&common->cmnd[7]));
347*e66d4537SJon Lin 
348*e66d4537SJon Lin 	if (unlikely(amount == 0)) {
349*e66d4537SJon Lin 		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
350*e66d4537SJon Lin 		rc = -EIO;
351*e66d4537SJon Lin 		goto out;
352*e66d4537SJon Lin 	}
353*e66d4537SJon Lin 
354*e66d4537SJon Lin 	/* Perform the erase */
355*e66d4537SJon Lin 	rc = ums[common->lun].erase_sector(&ums[common->lun],
356*e66d4537SJon Lin 					   file_offset,
357*e66d4537SJon Lin 					   amount);
358*e66d4537SJon Lin 	if (!rc) {
359*e66d4537SJon Lin 		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
360*e66d4537SJon Lin 		rc = -EIO;
361*e66d4537SJon Lin 	}
362*e66d4537SJon Lin 
363*e66d4537SJon Lin out:
364*e66d4537SJon Lin 	common->data_dir = DATA_DIR_NONE;
365*e66d4537SJon Lin 	bh->state = BUF_STATE_EMPTY;
366*e66d4537SJon Lin 
367*e66d4537SJon Lin 	return rc;
368*e66d4537SJon Lin }
369*e66d4537SJon Lin 
3700d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
3710d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
3720d0c3248SFrank Wang {
3730d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
3740d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
3750d0c3248SFrank Wang 	struct vendor_item	*vhead;
3760d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
3770d0c3248SFrank Wang 	void			*data;
3780d0c3248SFrank Wang 	int			rc;
3790d0c3248SFrank Wang 
3800d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
3810d0c3248SFrank Wang 		/* _MUST_ small than 64K */
3820d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
3830d0c3248SFrank Wang 		return -EINVAL;
3840d0c3248SFrank Wang 	}
3850d0c3248SFrank Wang 
3860d0c3248SFrank Wang 	common->residue         = common->data_size;
3870d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
3880d0c3248SFrank Wang 
3890d0c3248SFrank Wang 	/* Carry out the file writes */
3900d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
3910d0c3248SFrank Wang 		return -EIO; /* No data to write */
3920d0c3248SFrank Wang 
3930d0c3248SFrank Wang 	for (;;) {
3940d0c3248SFrank Wang 		if (common->usb_amount_left > 0) {
3950d0c3248SFrank Wang 			/* Wait for the next buffer to become available */
3960d0c3248SFrank Wang 			bh = common->next_buffhd_to_fill;
3970d0c3248SFrank Wang 			if (bh->state != BUF_STATE_EMPTY)
3980d0c3248SFrank Wang 				goto wait;
3990d0c3248SFrank Wang 
4000d0c3248SFrank Wang 			/* Request the next buffer */
4010d0c3248SFrank Wang 			common->usb_amount_left      -= common->data_size;
4020d0c3248SFrank Wang 			bh->outreq->length	     = common->data_size;
4030d0c3248SFrank Wang 			bh->bulk_out_intended_length = common->data_size;
4040d0c3248SFrank Wang 			bh->outreq->short_not_ok     = 1;
4050d0c3248SFrank Wang 
4060d0c3248SFrank Wang 			START_TRANSFER_OR(common, bulk_out, bh->outreq,
4070d0c3248SFrank Wang 					  &bh->outreq_busy, &bh->state)
4080d0c3248SFrank Wang 				/*
4090d0c3248SFrank Wang 				 * Don't know what to do if
4100d0c3248SFrank Wang 				 * common->fsg is NULL
4110d0c3248SFrank Wang 				 */
4120d0c3248SFrank Wang 				return -EIO;
4130d0c3248SFrank Wang 			common->next_buffhd_to_fill = bh->next;
4140d0c3248SFrank Wang 		} else {
4150d0c3248SFrank Wang 			/* Then, wait for the data to become available */
4160d0c3248SFrank Wang 			bh = common->next_buffhd_to_drain;
4170d0c3248SFrank Wang 			if (bh->state != BUF_STATE_FULL)
4180d0c3248SFrank Wang 				goto wait;
4190d0c3248SFrank Wang 
4200d0c3248SFrank Wang 			common->next_buffhd_to_drain = bh->next;
4210d0c3248SFrank Wang 			bh->state = BUF_STATE_EMPTY;
4220d0c3248SFrank Wang 
4230d0c3248SFrank Wang 			/* Did something go wrong with the transfer? */
4240d0c3248SFrank Wang 			if (bh->outreq->status != 0) {
4250d0c3248SFrank Wang 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
4260d0c3248SFrank Wang 				curlun->info_valid = 1;
4270d0c3248SFrank Wang 				break;
4280d0c3248SFrank Wang 			}
4290d0c3248SFrank Wang 
4300d0c3248SFrank Wang 			/* Perform the write */
4310d0c3248SFrank Wang 			vhead = (struct vendor_item *)bh->buf;
4320d0c3248SFrank Wang 			data  = bh->buf + sizeof(struct vendor_item);
4330d0c3248SFrank Wang 
4340d0c3248SFrank Wang 			if (!type) {
4350d0c3248SFrank Wang 				/* Vendor storage */
4360d0c3248SFrank Wang 				rc = vendor_storage_write(vhead->id,
4370d0c3248SFrank Wang 							  (char __user *)data,
4380d0c3248SFrank Wang 							  vhead->size);
43919652be0SFrank Wang 				if (rc < 0) {
44019652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
4410d0c3248SFrank Wang 					return -EIO;
44219652be0SFrank Wang 				}
4430d0c3248SFrank Wang 			} else {
4440d0c3248SFrank Wang 				/* RPMB */
4456f0347c8Stony.xu 				rc =
4466f0347c8Stony.xu 				write_keybox_to_secure_storage((u8 *)data,
4476f0347c8Stony.xu 							       vhead->size);
44819652be0SFrank Wang 				if (rc < 0) {
44919652be0SFrank Wang 					curlun->sense_data = SS_WRITE_ERROR;
4506f0347c8Stony.xu 					return -EIO;
4510d0c3248SFrank Wang 				}
45219652be0SFrank Wang 			}
4530d0c3248SFrank Wang 
4540d0c3248SFrank Wang 			common->residue -= common->data_size;
4550d0c3248SFrank Wang 
4560d0c3248SFrank Wang 			/* Did the host decide to stop early? */
4570d0c3248SFrank Wang 			if (bh->outreq->actual != bh->outreq->length)
4580d0c3248SFrank Wang 				common->short_packet_received = 1;
4590d0c3248SFrank Wang 			break; /* Command done */
4600d0c3248SFrank Wang 		}
4610d0c3248SFrank Wang wait:
4620d0c3248SFrank Wang 		/* Wait for something to happen */
4630d0c3248SFrank Wang 		rc = sleep_thread(common);
4640d0c3248SFrank Wang 		if (rc)
4650d0c3248SFrank Wang 			return rc;
4660d0c3248SFrank Wang 	}
4670d0c3248SFrank Wang 
4680d0c3248SFrank Wang 	return -EIO; /* No default reply */
4690d0c3248SFrank Wang }
4700d0c3248SFrank Wang 
4710d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
4720d0c3248SFrank Wang {
4730d0c3248SFrank Wang 	struct fsg_lun		*curlun = &common->luns[common->lun];
4740d0c3248SFrank Wang 	u16			type = get_unaligned_be16(&common->cmnd[4]);
4750d0c3248SFrank Wang 	struct vendor_item	*vhead;
4760d0c3248SFrank Wang 	struct fsg_buffhd	*bh;
4770d0c3248SFrank Wang 	void			*data;
4780d0c3248SFrank Wang 	int			rc;
4790d0c3248SFrank Wang 
4800d0c3248SFrank Wang 	if (common->data_size >= (u32)65536) {
4810d0c3248SFrank Wang 		/* _MUST_ small than 64K */
4820d0c3248SFrank Wang 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
4830d0c3248SFrank Wang 		return -EINVAL;
4840d0c3248SFrank Wang 	}
4850d0c3248SFrank Wang 
4860d0c3248SFrank Wang 	common->residue         = common->data_size;
4870d0c3248SFrank Wang 	common->usb_amount_left = common->data_size;
4880d0c3248SFrank Wang 
4890d0c3248SFrank Wang 	/* Carry out the file reads */
4900d0c3248SFrank Wang 	if (unlikely(common->data_size == 0))
4910d0c3248SFrank Wang 		return -EIO; /* No default reply */
4920d0c3248SFrank Wang 
4930d0c3248SFrank Wang 	for (;;) {
4940d0c3248SFrank Wang 		/* Wait for the next buffer to become available */
4950d0c3248SFrank Wang 		bh = common->next_buffhd_to_fill;
4960d0c3248SFrank Wang 		while (bh->state != BUF_STATE_EMPTY) {
4970d0c3248SFrank Wang 			rc = sleep_thread(common);
4980d0c3248SFrank Wang 			if (rc)
4990d0c3248SFrank Wang 				return rc;
5000d0c3248SFrank Wang 		}
5010d0c3248SFrank Wang 
5020d0c3248SFrank Wang 		memset(bh->buf, 0, FSG_BUFLEN);
5030d0c3248SFrank Wang 		vhead = (struct vendor_item *)bh->buf;
5040d0c3248SFrank Wang 		data  = bh->buf + sizeof(struct vendor_item);
5050d0c3248SFrank Wang 		vhead->id = get_unaligned_be16(&common->cmnd[2]);
5060d0c3248SFrank Wang 
5070d0c3248SFrank Wang 		if (!type) {
5080d0c3248SFrank Wang 			/* Vendor storage */
5090d0c3248SFrank Wang 			rc = vendor_storage_read(vhead->id,
5100d0c3248SFrank Wang 						 (char __user *)data,
5110d0c3248SFrank Wang 						 common->data_size);
51219652be0SFrank Wang 			if (!rc) {
51319652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
5140d0c3248SFrank Wang 				return -EIO;
51519652be0SFrank Wang 			}
5160d0c3248SFrank Wang 			vhead->size = rc;
5170d0c3248SFrank Wang 		} else {
5180d0c3248SFrank Wang 			/* RPMB */
519700a3668STony Xu 			rc =
520700a3668STony Xu 			read_raw_data_from_secure_storage((u8 *)data,
521700a3668STony Xu 							  common->data_size);
52219652be0SFrank Wang 			if (!rc) {
52319652be0SFrank Wang 				curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
524700a3668STony Xu 				return -EIO;
52519652be0SFrank Wang 			}
526700a3668STony Xu 			vhead->size = rc;
5270d0c3248SFrank Wang 		}
5280d0c3248SFrank Wang 
5290d0c3248SFrank Wang 		common->residue   -= common->data_size;
5300d0c3248SFrank Wang 		bh->inreq->length = common->data_size;
5310d0c3248SFrank Wang 		bh->state         = BUF_STATE_FULL;
5320d0c3248SFrank Wang 
5330d0c3248SFrank Wang 		break; /* No more left to read */
5340d0c3248SFrank Wang 	}
5350d0c3248SFrank Wang 
5360d0c3248SFrank Wang 	return -EIO; /* No default reply */
5370d0c3248SFrank Wang }
5380d0c3248SFrank Wang #endif
5390d0c3248SFrank Wang 
540f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
541f16e43f8SFrank Wang 				  struct fsg_buffhd *bh)
542f16e43f8SFrank Wang {
543f16e43f8SFrank Wang 	u8 *buf = (u8 *)bh->buf;
544f16e43f8SFrank Wang 	u32 len = common->data_size;
545d015bf41SFrank Wang 	enum if_type type = ums[common->lun].block_dev.if_type;
546*e66d4537SJon Lin 	int devnum = ums[common->lun].block_dev.devnum;
547f16e43f8SFrank Wang 
548f16e43f8SFrank Wang 	/*
549f16e43f8SFrank Wang 	 * bit[0]: Direct LBA, 0: Disabled;
5500d0c3248SFrank Wang 	 * bit[1]: Vendor Storage API, 0: Disabed (default);
551d015bf41SFrank Wang 	 * bit[2]: First 4M Access, 0: Disabled;
5520d0c3248SFrank Wang 	 * bit[3]: Read LBA On, 0: Disabed (default);
5530d0c3248SFrank Wang 	 * bit[4]: New Vendor Storage API, 0: Disabed;
5540d0c3248SFrank Wang 	 * bit[5:63}: Reserved.
555f16e43f8SFrank Wang 	 */
556f16e43f8SFrank Wang 	memset((void *)&buf[0], 0, len);
557af5a2012SJason Zhu 	if (type == IF_TYPE_MMC || type == IF_TYPE_SD)
5580d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(2) | BIT(4);
5590d0c3248SFrank Wang 	else
5600d0c3248SFrank Wang 		buf[0] = BIT(0) | BIT(4);
561f16e43f8SFrank Wang 
562*e66d4537SJon Lin 	if (type == IF_TYPE_MTD &&
563*e66d4537SJon Lin 	    (devnum == BLK_MTD_NAND ||
564*e66d4537SJon Lin 	    devnum == BLK_MTD_SPI_NAND))
565*e66d4537SJon Lin 		buf[0] |= (1 << 6);
566*e66d4537SJon Lin 
567f16e43f8SFrank Wang 	/* Set data xfer size */
568*e66d4537SJon Lin 	common->residue = len;
569*e66d4537SJon Lin 	common->data_size_from_cmnd = len;
570f16e43f8SFrank Wang 
571f16e43f8SFrank Wang 	return len;
572f16e43f8SFrank Wang }
573f16e43f8SFrank Wang 
574d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
575d23ec8c4SKever Yang 			      struct fsg_buffhd *bh)
576d23ec8c4SKever Yang {
577d23ec8c4SKever Yang 	struct usb_request      *req = bh->outreq;
578d23ec8c4SKever Yang 	struct fsg_bulk_cb_wrap *cbw = req->buf;
579d23ec8c4SKever Yang 
580d23ec8c4SKever Yang 	/* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
581d23ec8c4SKever Yang 	common->data_size = le32_to_cpu(cbw->DataTransferLength);
582d23ec8c4SKever Yang 	if (common->data_size == 0) {
583d23ec8c4SKever Yang 		common->data_size =
584d23ec8c4SKever Yang 		get_unaligned_be16(&common->cmnd[7]) << 9;
585d23ec8c4SKever Yang 		printf("Trasfer Length NOT set, please use new version tool\n");
586d23ec8c4SKever Yang 		debug("%s %d, cmnd1 %x\n", __func__,
587d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[7]),
588d23ec8c4SKever Yang 		      get_unaligned_be16(&common->cmnd[1]));
589d23ec8c4SKever Yang 	}
590d23ec8c4SKever Yang 	if (cbw->Flags & USB_BULK_IN_FLAG)
591d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_TO_HOST;
592d23ec8c4SKever Yang 	else
593d23ec8c4SKever Yang 		common->data_dir = DATA_DIR_FROM_HOST;
594d23ec8c4SKever Yang 
595d23ec8c4SKever Yang 	/* Not support */
596d23ec8c4SKever Yang 	common->cmnd[1] = 0;
597d23ec8c4SKever Yang }
598d23ec8c4SKever Yang 
599f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
600f16e43f8SFrank Wang 			     struct fsg_buffhd *bh, int *reply)
601f16e43f8SFrank Wang {
602f16e43f8SFrank Wang 	struct usb_request	*req = bh->outreq;
603f16e43f8SFrank Wang 	struct fsg_bulk_cb_wrap	*cbw = req->buf;
604f16e43f8SFrank Wang 	int rc;
605f16e43f8SFrank Wang 
606f16e43f8SFrank Wang 	dump_cbw(cbw);
607f16e43f8SFrank Wang 
608f16e43f8SFrank Wang 	if (rkusb_check_lun(common)) {
609f16e43f8SFrank Wang 		*reply = -EINVAL;
610f16e43f8SFrank Wang 		return RKUSB_RC_ERROR;
611f16e43f8SFrank Wang 	}
612f16e43f8SFrank Wang 
613f16e43f8SFrank Wang 	switch (common->cmnd[0]) {
614f16e43f8SFrank Wang 	case RKUSB_TEST_UNIT_READY:
615f16e43f8SFrank Wang 		*reply = rkusb_do_test_unit_ready(common, bh);
616f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
617f16e43f8SFrank Wang 		break;
618f16e43f8SFrank Wang 
619f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_ID:
620f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_id(common, bh);
621f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
622f16e43f8SFrank Wang 		break;
623f16e43f8SFrank Wang 
624f16e43f8SFrank Wang 	case RKUSB_TEST_BAD_BLOCK:
625f16e43f8SFrank Wang 		*reply = rkusb_do_test_bad_block(common, bh);
626f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
627f16e43f8SFrank Wang 		break;
628f16e43f8SFrank Wang 
629*e66d4537SJon Lin 	case RKUSB_ERASE_10_FORCE:
630*e66d4537SJon Lin 		*reply = rkusb_do_erase_force(common, bh);
631*e66d4537SJon Lin 		rc = RKUSB_RC_FINISHED;
632*e66d4537SJon Lin 		break;
633*e66d4537SJon Lin 
634f16e43f8SFrank Wang 	case RKUSB_LBA_READ_10:
6355fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
636f16e43f8SFrank Wang 		common->cmnd[0] = SC_READ_10;
637f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
638f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
639f16e43f8SFrank Wang 		break;
640f16e43f8SFrank Wang 
641f16e43f8SFrank Wang 	case RKUSB_LBA_WRITE_10:
6425fb597c2SKever Yang 		rkusb_fixup_cbwcb(common, bh);
643f16e43f8SFrank Wang 		common->cmnd[0] = SC_WRITE_10;
644f16e43f8SFrank Wang 		common->cmnd[1] = 0; /* Not support */
645f16e43f8SFrank Wang 		rc = RKUSB_RC_CONTINUE;
646f16e43f8SFrank Wang 		break;
647f16e43f8SFrank Wang 
648f16e43f8SFrank Wang 	case RKUSB_READ_FLASH_INFO:
649f16e43f8SFrank Wang 		*reply = rkusb_do_read_flash_info(common, bh);
650f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
651f16e43f8SFrank Wang 		break;
652f16e43f8SFrank Wang 
653829f2b85SFrank Wang 	case RKUSB_GET_CHIP_VER:
654829f2b85SFrank Wang 		*reply = rkusb_do_get_chip_info(common, bh);
655829f2b85SFrank Wang 		rc = RKUSB_RC_FINISHED;
656829f2b85SFrank Wang 		break;
657829f2b85SFrank Wang 
658f16e43f8SFrank Wang 	case RKUSB_LBA_ERASE:
659f16e43f8SFrank Wang 		*reply = rkusb_do_lba_erase(common, bh);
660f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
661f16e43f8SFrank Wang 		break;
662f16e43f8SFrank Wang 
6630d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
6640d0c3248SFrank Wang 	case RKUSB_VS_WRITE:
6650d0c3248SFrank Wang 		*reply = rkusb_do_vs_write(common);
6660d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
6670d0c3248SFrank Wang 		break;
6680d0c3248SFrank Wang 
6690d0c3248SFrank Wang 	case RKUSB_VS_READ:
6700d0c3248SFrank Wang 		*reply = rkusb_do_vs_read(common);
6710d0c3248SFrank Wang 		rc = RKUSB_RC_FINISHED;
6720d0c3248SFrank Wang 		break;
6730d0c3248SFrank Wang #endif
6740d0c3248SFrank Wang 
675f16e43f8SFrank Wang 	case RKUSB_READ_CAPACITY:
676f16e43f8SFrank Wang 		*reply = rkusb_do_read_capacity(common, bh);
677f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
678f16e43f8SFrank Wang 		break;
679f16e43f8SFrank Wang 
680f16e43f8SFrank Wang 	case RKUSB_RESET:
681f16e43f8SFrank Wang 		*reply = rkusb_do_reset(common, bh);
682f16e43f8SFrank Wang 		rc = RKUSB_RC_FINISHED;
683f16e43f8SFrank Wang 		break;
684f16e43f8SFrank Wang 
685f16e43f8SFrank Wang 	case RKUSB_READ_10:
686f16e43f8SFrank Wang 	case RKUSB_WRITE_10:
687e0023032SKever Yang 		printf("CMD Not support, pls use new version Tool\n");
688e0023032SKever Yang 	case RKUSB_SET_DEVICE_ID:
689f16e43f8SFrank Wang 	case RKUSB_ERASE_10:
690f16e43f8SFrank Wang 	case RKUSB_WRITE_SPARE:
691f16e43f8SFrank Wang 	case RKUSB_READ_SPARE:
692f16e43f8SFrank Wang 	case RKUSB_GET_VERSION:
693f16e43f8SFrank Wang 	case RKUSB_ERASE_SYS_DISK:
694f16e43f8SFrank Wang 	case RKUSB_SDRAM_READ_10:
695f16e43f8SFrank Wang 	case RKUSB_SDRAM_WRITE_10:
696f16e43f8SFrank Wang 	case RKUSB_SDRAM_EXECUTE:
697f16e43f8SFrank Wang 	case RKUSB_LOW_FORMAT:
698f16e43f8SFrank Wang 	case RKUSB_SET_RESET_FLAG:
699f16e43f8SFrank Wang 	case RKUSB_SPI_READ_10:
700f16e43f8SFrank Wang 	case RKUSB_SPI_WRITE_10:
701f16e43f8SFrank Wang 	case RKUSB_SESSION:
702f16e43f8SFrank Wang 		/* Fall through */
703f16e43f8SFrank Wang 	default:
704f16e43f8SFrank Wang 		rc = RKUSB_RC_UNKNOWN_CMND;
705f16e43f8SFrank Wang 		break;
706f16e43f8SFrank Wang 	}
707f16e43f8SFrank Wang 
708f16e43f8SFrank Wang 	return rc;
709f16e43f8SFrank Wang }
710f16e43f8SFrank Wang 
711f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
712