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>
178168f857SYifeng Zhao #include <dm.h>
188168f857SYifeng Zhao #include <misc.h>
194d2787f5SJon Lin #include <mmc.h>
201b375c35SYifeng Zhao #include <scsi.h>
214d2787f5SJon Lin #include <stdlib.h>
228c6654f1SJon Lin #include <usbplug.h>
230d0c3248SFrank Wang #include <asm/arch/vendor.h>
24f16e43f8SFrank Wang #include <rockusb.h>
25f16e43f8SFrank Wang
26f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS 0xff
27f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS 0x06
28f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL 0x05
29f16e43f8SFrank Wang
30e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE 1024
31e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE 4
32e66d4537SJon Lin
33f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = {
34f16e43f8SFrank Wang .bLength = USB_DT_INTERFACE_SIZE,
35f16e43f8SFrank Wang .bDescriptorType = USB_DT_INTERFACE,
36f16e43f8SFrank Wang .bInterfaceNumber = 0x00,
37f16e43f8SFrank Wang .bAlternateSetting = 0x00,
38f16e43f8SFrank Wang .bNumEndpoints = 0x02,
39f16e43f8SFrank Wang .bInterfaceClass = ROCKUSB_INTERFACE_CLASS,
40f16e43f8SFrank Wang .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS,
41f16e43f8SFrank Wang .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL,
42f16e43f8SFrank Wang };
43f16e43f8SFrank Wang
44f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = {
45f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc,
46f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_in_desc,
47f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_out_desc,
48f16e43f8SFrank Wang NULL,
49f16e43f8SFrank Wang };
50f16e43f8SFrank Wang
51f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = {
52f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc,
53f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_in_desc,
54f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_out_desc,
55f16e43f8SFrank Wang NULL,
56f16e43f8SFrank Wang };
57f16e43f8SFrank Wang
5826dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = {
5926dd3474SWilliam Wu (struct usb_descriptor_header *)&rkusb_intf_desc,
6026dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_desc,
6126dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc,
6226dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_desc,
6326dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc,
6426dd3474SWilliam Wu NULL,
6526dd3474SWilliam Wu };
6626dd3474SWilliam Wu
67f16e43f8SFrank Wang struct rk_flash_info {
68f16e43f8SFrank Wang u32 flash_size;
69f16e43f8SFrank Wang u16 block_size;
70f16e43f8SFrank Wang u8 page_size;
71f16e43f8SFrank Wang u8 ecc_bits;
72f16e43f8SFrank Wang u8 access_time;
73f16e43f8SFrank Wang u8 manufacturer;
74f16e43f8SFrank Wang u8 flash_mask;
75f16e43f8SFrank Wang } __packed;
76f16e43f8SFrank Wang
775b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */
785b081643SFrank Wang
g_dnl_bind_fixup(struct usb_device_descriptor * dev,const char * name)79f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
80f16e43f8SFrank Wang {
81ba437c8cSFrank Wang if (IS_RKUSB_UMS_DNL(name)) {
82c0acb0f2SFrank Wang /* Fix to Rockchip's VID and PID */
83ba437c8cSFrank Wang dev->idVendor = __constant_cpu_to_le16(0x2207);
84ba437c8cSFrank Wang dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID);
85ba437c8cSFrank Wang
86f16e43f8SFrank Wang /* Enumerate as a loader device */
8795424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG)
8895424692SJoseph Chen dev->bcdUSB = cpu_to_le16(0x0200);
8995424692SJoseph Chen #else
90f16e43f8SFrank Wang dev->bcdUSB = cpu_to_le16(0x0201);
9195424692SJoseph Chen #endif
92c0acb0f2SFrank Wang } else if (!strncmp(name, "usb_dnl_fastboot", 16)) {
93c0acb0f2SFrank Wang /* Fix to Google's VID and PID */
94c0acb0f2SFrank Wang dev->idVendor = __constant_cpu_to_le16(0x18d1);
959aae75f9SWilliam Wu dev->idProduct = __constant_cpu_to_le16(0x4d00);
96ca422507SYifeng Zhao } else if (!strncmp(name, "usb_dnl_dfu", 11)) {
97ca422507SYifeng Zhao /* Fix to Rockchip's VID and PID for DFU */
98ca422507SYifeng Zhao dev->idVendor = cpu_to_le16(0x2207);
99ca422507SYifeng Zhao dev->idProduct = cpu_to_le16(0x0107);
1000a076251SFrank Wang } else if (!strncmp(name, "usb_dnl_ums", 11)) {
1010a076251SFrank Wang dev->idVendor = cpu_to_le16(0x2207);
1020a076251SFrank Wang dev->idProduct = cpu_to_le16(0x0010);
103ba437c8cSFrank Wang }
104f16e43f8SFrank Wang
105f16e43f8SFrank Wang return 0;
106f16e43f8SFrank Wang }
107f16e43f8SFrank Wang
108f16e43f8SFrank Wang __maybe_unused
dump_cbw(struct fsg_bulk_cb_wrap * cbw)109f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw)
110f16e43f8SFrank Wang {
111f16e43f8SFrank Wang assert(!cbw);
112f16e43f8SFrank Wang
113f16e43f8SFrank Wang debug("%s:\n", __func__);
114f16e43f8SFrank Wang debug("Signature %x\n", cbw->Signature);
115f16e43f8SFrank Wang debug("Tag %x\n", cbw->Tag);
116f16e43f8SFrank Wang debug("DataTransferLength %x\n", cbw->DataTransferLength);
117f16e43f8SFrank Wang debug("Flags %x\n", cbw->Flags);
118f16e43f8SFrank Wang debug("LUN %x\n", cbw->Lun);
119f16e43f8SFrank Wang debug("Length %x\n", cbw->Length);
120f16e43f8SFrank Wang debug("OptionCode %x\n", cbw->CDB[0]);
121f16e43f8SFrank Wang debug("SubCode %x\n", cbw->CDB[1]);
122f16e43f8SFrank Wang debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2]));
123f16e43f8SFrank Wang debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7]));
124f16e43f8SFrank Wang }
125f16e43f8SFrank Wang
rkusb_check_lun(struct fsg_common * common)126f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common)
127f16e43f8SFrank Wang {
128f16e43f8SFrank Wang struct fsg_lun *curlun;
129f16e43f8SFrank Wang
130f16e43f8SFrank Wang /* Check the LUN */
131f16e43f8SFrank Wang if (common->lun >= 0 && common->lun < common->nluns) {
132f16e43f8SFrank Wang curlun = &common->luns[common->lun];
133f16e43f8SFrank Wang if (common->cmnd[0] != SC_REQUEST_SENSE) {
134f16e43f8SFrank Wang curlun->sense_data = SS_NO_SENSE;
135f16e43f8SFrank Wang curlun->info_valid = 0;
136f16e43f8SFrank Wang }
137f16e43f8SFrank Wang } else {
138f16e43f8SFrank Wang curlun = NULL;
139f16e43f8SFrank Wang common->bad_lun_okay = 0;
140f16e43f8SFrank Wang
141f16e43f8SFrank Wang /*
142f16e43f8SFrank Wang * INQUIRY and REQUEST SENSE commands are explicitly allowed
143f16e43f8SFrank Wang * to use unsupported LUNs; all others may not.
144f16e43f8SFrank Wang */
145f16e43f8SFrank Wang if (common->cmnd[0] != SC_INQUIRY &&
146f16e43f8SFrank Wang common->cmnd[0] != SC_REQUEST_SENSE) {
147f16e43f8SFrank Wang debug("unsupported LUN %d\n", common->lun);
148f16e43f8SFrank Wang return -EINVAL;
149f16e43f8SFrank Wang }
150f16e43f8SFrank Wang }
151f16e43f8SFrank Wang
152f16e43f8SFrank Wang return 0;
153f16e43f8SFrank Wang }
154f16e43f8SFrank Wang
__do_reset(struct usb_ep * ep,struct usb_request * req)155f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req)
156f16e43f8SFrank Wang {
1575b081643SFrank Wang u32 boot_flag = BOOT_NORMAL;
1585b081643SFrank Wang
1595b081643SFrank Wang if (rkusb_rst_code == 0x03)
1605b081643SFrank Wang boot_flag = BOOT_BROM_DOWNLOAD;
161*a7d1e51cSJon Lin else if (rkusb_rst_code == 0x06)
162*a7d1e51cSJon Lin boot_flag = BOOT_LOADER;
1635b081643SFrank Wang
1645b081643SFrank Wang rkusb_rst_code = 0; /* restore to default */
1655b081643SFrank Wang writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
166866d7966SJoseph Chen
167f16e43f8SFrank Wang do_reset(NULL, 0, 0, NULL);
168f16e43f8SFrank Wang }
169f16e43f8SFrank Wang
rkusb_do_reset(struct fsg_common * common,struct fsg_buffhd * bh)170f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common,
171f16e43f8SFrank Wang struct fsg_buffhd *bh)
172f16e43f8SFrank Wang {
173f16e43f8SFrank Wang common->data_size_from_cmnd = common->cmnd[4];
174f16e43f8SFrank Wang common->residue = 0;
175f16e43f8SFrank Wang bh->inreq->complete = __do_reset;
176f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY;
177f16e43f8SFrank Wang
1785b081643SFrank Wang rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1];
179f16e43f8SFrank Wang return 0;
180f16e43f8SFrank Wang }
181f16e43f8SFrank Wang
rkusb_usb3_capable(void)18236c87911Swilliam.wu __weak bool rkusb_usb3_capable(void)
18336c87911Swilliam.wu {
18436c87911Swilliam.wu return false;
18536c87911Swilliam.wu }
18636c87911Swilliam.wu
rkusb_do_switch_to_usb3(struct fsg_common * common,struct fsg_buffhd * bh)18736c87911Swilliam.wu static int rkusb_do_switch_to_usb3(struct fsg_common *common,
18836c87911Swilliam.wu struct fsg_buffhd *bh)
18936c87911Swilliam.wu {
19036c87911Swilliam.wu g_dnl_set_serialnumber((char *)&common->cmnd[1]);
19136c87911Swilliam.wu rkusb_switch_to_usb3_enable(true);
19236c87911Swilliam.wu bh->state = BUF_STATE_EMPTY;
19336c87911Swilliam.wu
19436c87911Swilliam.wu return 0;
19536c87911Swilliam.wu }
19636c87911Swilliam.wu
rkusb_do_test_unit_ready(struct fsg_common * common,struct fsg_buffhd * bh)197f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common,
198f16e43f8SFrank Wang struct fsg_buffhd *bh)
199f16e43f8SFrank Wang {
2007eb64117SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev;
20118188f57SWilliam Wu u32 usb_trb_size;
20218188f57SWilliam Wu u16 residue;
2037eb64117SJon Lin
2047eb64117SJon Lin if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) ||
2057eb64117SJon Lin desc->if_type == IF_TYPE_SPINOR)
20618188f57SWilliam Wu residue = 0x03; /* 128KB Max block xfer for SPI Nor */
20718188f57SWilliam Wu else if (common->cmnd[1] == 0xf7 && FSG_BUFLEN >= 0x400000)
20818188f57SWilliam Wu residue = 0x0a; /* Max block xfer for USB DWC3 */
2097eb64117SJon Lin else
21018188f57SWilliam Wu residue = 0x06; /* Max block xfer support from host */
2117eb64117SJon Lin
21218188f57SWilliam Wu usb_trb_size = (1 << residue) * 4096;
21318188f57SWilliam Wu common->usb_trb_size = min(usb_trb_size, FSG_BUFLEN);
21418188f57SWilliam Wu common->residue = residue << 24;
215f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE;
216f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY;
217f16e43f8SFrank Wang
218f16e43f8SFrank Wang return 0;
219f16e43f8SFrank Wang }
220f16e43f8SFrank Wang
rkusb_do_read_flash_id(struct fsg_common * common,struct fsg_buffhd * bh)221f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common,
222f16e43f8SFrank Wang struct fsg_buffhd *bh)
223f16e43f8SFrank Wang {
224f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf;
225e0023032SKever Yang u32 len = 5;
226d7386f60SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type;
227afc6362aSJon Lin u32 devnum = ums[common->lun].block_dev.devnum;
228afc6362aSJon Lin const char *str;
229f16e43f8SFrank Wang
230afc6362aSJon Lin switch (type) {
231afc6362aSJon Lin case IF_TYPE_MMC:
232afc6362aSJon Lin str = "EMMC ";
233afc6362aSJon Lin break;
234afc6362aSJon Lin case IF_TYPE_RKNAND:
235afc6362aSJon Lin str = "NAND ";
236afc6362aSJon Lin break;
237afc6362aSJon Lin case IF_TYPE_MTD:
238afc6362aSJon Lin if (devnum == BLK_MTD_SPI_NAND)
239afc6362aSJon Lin str ="SNAND";
240afc6362aSJon Lin else if (devnum == BLK_MTD_NAND)
241afc6362aSJon Lin str = "NAND ";
242d7386f60SFrank Wang else
243afc6362aSJon Lin str = "NOR ";
244afc6362aSJon Lin break;
24591eda203SYifeng Zhao case IF_TYPE_SCSI:
24691eda203SYifeng Zhao str = "SATA ";
24791eda203SYifeng Zhao break;
24891eda203SYifeng Zhao case IF_TYPE_NVME:
24991eda203SYifeng Zhao str = "PCIE ";
25091eda203SYifeng Zhao break;
251afc6362aSJon Lin default:
252afc6362aSJon Lin str = "UNKN "; /* unknown */
253afc6362aSJon Lin break;
254afc6362aSJon Lin }
255afc6362aSJon Lin
256afc6362aSJon Lin memcpy((void *)&buf[0], str, len);
257f16e43f8SFrank Wang
258f16e43f8SFrank Wang /* Set data xfer size */
259f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len;
260e0023032SKever Yang common->data_size = len;
261f16e43f8SFrank Wang
262f16e43f8SFrank Wang return len;
263f16e43f8SFrank Wang }
264f16e43f8SFrank Wang
rkusb_do_test_bad_block(struct fsg_common * common,struct fsg_buffhd * bh)265f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common,
266f16e43f8SFrank Wang struct fsg_buffhd *bh)
267f16e43f8SFrank Wang {
268f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf;
269e0023032SKever Yang u32 len = 64;
270f16e43f8SFrank Wang
271f16e43f8SFrank Wang memset((void *)&buf[0], 0, len);
272f16e43f8SFrank Wang
273f16e43f8SFrank Wang /* Set data xfer size */
274f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len;
275e0023032SKever Yang common->data_size = len;
276f16e43f8SFrank Wang
277f16e43f8SFrank Wang return len;
278f16e43f8SFrank Wang }
279f16e43f8SFrank Wang
rkusb_do_read_flash_info(struct fsg_common * common,struct fsg_buffhd * bh)280f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common,
281f16e43f8SFrank Wang struct fsg_buffhd *bh)
282f16e43f8SFrank Wang {
283e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev;
284f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf;
285d23ec8c4SKever Yang u32 len = sizeof(struct rk_flash_info);
286f16e43f8SFrank Wang struct rk_flash_info finfo = {
287e66d4537SJon Lin .block_size = ROCKCHIP_FLASH_BLOCK_SIZE,
288f16e43f8SFrank Wang .ecc_bits = 0,
289e66d4537SJon Lin .page_size = ROCKCHIP_FLASH_PAGE_SIZE,
290f16e43f8SFrank Wang .access_time = 40,
291f16e43f8SFrank Wang .manufacturer = 0,
292f16e43f8SFrank Wang .flash_mask = 0
293f16e43f8SFrank Wang };
294f16e43f8SFrank Wang
2950aca89f2SYifeng Zhao /* Set the raw block size for tools to creat GPT with 4K block size */
2960aca89f2SYifeng Zhao if (desc->rawblksz == 0x1000)
2970aca89f2SYifeng Zhao finfo.manufacturer = 208;
2980aca89f2SYifeng Zhao
299e66d4537SJon Lin finfo.flash_size = (u32)desc->lba;
300e66d4537SJon Lin
301e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD &&
302e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND ||
303e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) {
304e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
305e66d4537SJon Lin
306e66d4537SJon Lin if (mtd) {
307e66d4537SJon Lin finfo.block_size = mtd->erasesize >> 9;
308e66d4537SJon Lin finfo.page_size = mtd->writesize >> 9;
30926b169f6SJon Lin #ifdef CONFIG_SUPPORT_USBPLUG
31026b169f6SJon Lin /* Using 4KB pagesize as 2KB for idblock */
31126b169f6SJon Lin if (finfo.page_size == 8 && desc->devnum == BLK_MTD_SPI_NAND)
31226b169f6SJon Lin finfo.page_size |= (4 << 4);
31326b169f6SJon Lin #endif
314e66d4537SJon Lin }
315e66d4537SJon Lin }
316e66d4537SJon Lin
31765a0fed9SJon Lin if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) {
318398ff6a5SJon Lin /* RV1126 mtd spinor keep the former upgrade mode */
319398ff6a5SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126)
320b8e5601dSJon Lin finfo.block_size = 0x80; /* Aligned to 64KB */
32165a0fed9SJon Lin #else
32265a0fed9SJon Lin finfo.block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
32365a0fed9SJon Lin #endif
324398ff6a5SJon Lin #if defined(CONFIG_ROCKCHIP_RK3308)
325398ff6a5SJon Lin } else if (desc->if_type == IF_TYPE_SPINOR) {
326398ff6a5SJon Lin finfo.block_size = 0x80; /* Aligned to 64KB */
327398ff6a5SJon Lin #endif
32865a0fed9SJon Lin }
32965a0fed9SJon Lin
330e66d4537SJon Lin debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size,
331e66d4537SJon Lin finfo.page_size);
332e66d4537SJon Lin
333f16e43f8SFrank Wang if (finfo.flash_size)
334f16e43f8SFrank Wang finfo.flash_mask = 1;
335f16e43f8SFrank Wang
336f16e43f8SFrank Wang memset((void *)&buf[0], 0, len);
337f16e43f8SFrank Wang memcpy((void *)&buf[0], (void *)&finfo, len);
338f16e43f8SFrank Wang
339f16e43f8SFrank Wang /* Set data xfer size */
340f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len;
341d23ec8c4SKever Yang /* legacy upgrade_tool does not set correct transfer size */
342d23ec8c4SKever Yang common->data_size = len;
343f16e43f8SFrank Wang
344f16e43f8SFrank Wang return len;
345f16e43f8SFrank Wang }
346f16e43f8SFrank Wang
rkusb_do_get_chip_info(struct fsg_common * common,struct fsg_buffhd * bh)347829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common,
348829f2b85SFrank Wang struct fsg_buffhd *bh)
349829f2b85SFrank Wang {
350829f2b85SFrank Wang u8 *buf = (u8 *)bh->buf;
351829f2b85SFrank Wang u32 len = common->data_size;
352829f2b85SFrank Wang u32 chip_info[4];
353829f2b85SFrank Wang
354829f2b85SFrank Wang memset((void *)chip_info, 0, sizeof(chip_info));
355829f2b85SFrank Wang rockchip_rockusb_get_chip_info(chip_info);
356829f2b85SFrank Wang
357829f2b85SFrank Wang memset((void *)&buf[0], 0, len);
358829f2b85SFrank Wang memcpy((void *)&buf[0], (void *)chip_info, len);
359829f2b85SFrank Wang
360829f2b85SFrank Wang /* Set data xfer size */
361829f2b85SFrank Wang common->residue = common->data_size_from_cmnd = len;
362829f2b85SFrank Wang
363829f2b85SFrank Wang return len;
364829f2b85SFrank Wang }
365829f2b85SFrank Wang
rkusb_do_lba_erase(struct fsg_common * common,struct fsg_buffhd * bh)366f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common,
367f16e43f8SFrank Wang struct fsg_buffhd *bh)
368f16e43f8SFrank Wang {
369f16e43f8SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun];
370f16e43f8SFrank Wang u32 lba, amount;
371f16e43f8SFrank Wang loff_t file_offset;
372f16e43f8SFrank Wang int rc;
373f16e43f8SFrank Wang
374f16e43f8SFrank Wang lba = get_unaligned_be32(&common->cmnd[2]);
375f16e43f8SFrank Wang if (lba >= curlun->num_sectors) {
376f16e43f8SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
377f16e43f8SFrank Wang rc = -EINVAL;
378f16e43f8SFrank Wang goto out;
379f16e43f8SFrank Wang }
380f16e43f8SFrank Wang
381f16e43f8SFrank Wang file_offset = ((loff_t) lba) << 9;
382f16e43f8SFrank Wang amount = get_unaligned_be16(&common->cmnd[7]) << 9;
383f16e43f8SFrank Wang if (unlikely(amount == 0)) {
384f16e43f8SFrank Wang curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
385f16e43f8SFrank Wang rc = -EIO;
386f16e43f8SFrank Wang goto out;
387f16e43f8SFrank Wang }
388f16e43f8SFrank Wang
389f16e43f8SFrank Wang /* Perform the erase */
390f16e43f8SFrank Wang rc = ums[common->lun].erase_sector(&ums[common->lun],
391f16e43f8SFrank Wang file_offset / SECTOR_SIZE,
392f16e43f8SFrank Wang amount / SECTOR_SIZE);
393f16e43f8SFrank Wang if (!rc) {
394f16e43f8SFrank Wang curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
395f16e43f8SFrank Wang rc = -EIO;
396f16e43f8SFrank Wang }
397f16e43f8SFrank Wang
398f16e43f8SFrank Wang out:
399f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE;
400f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY;
401f16e43f8SFrank Wang
402f16e43f8SFrank Wang return rc;
403f16e43f8SFrank Wang }
404f16e43f8SFrank Wang
rkusb_do_erase_force(struct fsg_common * common,struct fsg_buffhd * bh)405e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common,
406e66d4537SJon Lin struct fsg_buffhd *bh)
407e66d4537SJon Lin {
408e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev;
409e66d4537SJon Lin struct fsg_lun *curlun = &common->luns[common->lun];
410e66d4537SJon Lin u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE;
411e66d4537SJon Lin u32 lba, amount;
412e66d4537SJon Lin loff_t file_offset;
413e66d4537SJon Lin int rc;
414e66d4537SJon Lin
415e66d4537SJon Lin lba = get_unaligned_be32(&common->cmnd[2]);
416e66d4537SJon Lin if (lba >= curlun->num_sectors) {
417e66d4537SJon Lin curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
418e66d4537SJon Lin rc = -EINVAL;
419e66d4537SJon Lin goto out;
420e66d4537SJon Lin }
421e66d4537SJon Lin
422e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD &&
423e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND ||
424e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) {
425e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv;
426e66d4537SJon Lin
427e66d4537SJon Lin if (mtd)
428e66d4537SJon Lin block_size = mtd->erasesize >> 9;
429e66d4537SJon Lin }
430e66d4537SJon Lin
431e66d4537SJon Lin file_offset = ((loff_t)lba) * block_size;
432e66d4537SJon Lin amount = get_unaligned_be16(&common->cmnd[7]) * block_size;
433e66d4537SJon Lin
434e66d4537SJon Lin debug("%s lba= %x, nsec= %x\n", __func__, lba,
435e66d4537SJon Lin (u32)get_unaligned_be16(&common->cmnd[7]));
436e66d4537SJon Lin
437e66d4537SJon Lin if (unlikely(amount == 0)) {
438e66d4537SJon Lin curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
439e66d4537SJon Lin rc = -EIO;
440e66d4537SJon Lin goto out;
441e66d4537SJon Lin }
442e66d4537SJon Lin
443e66d4537SJon Lin /* Perform the erase */
444e66d4537SJon Lin rc = ums[common->lun].erase_sector(&ums[common->lun],
445e66d4537SJon Lin file_offset,
446e66d4537SJon Lin amount);
447e66d4537SJon Lin if (!rc) {
448e66d4537SJon Lin curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
449e66d4537SJon Lin rc = -EIO;
450e66d4537SJon Lin }
451e66d4537SJon Lin
452e66d4537SJon Lin out:
453e66d4537SJon Lin common->data_dir = DATA_DIR_NONE;
454e66d4537SJon Lin bh->state = BUF_STATE_EMPTY;
455e66d4537SJon Lin
456e66d4537SJon Lin return rc;
457e66d4537SJon Lin }
458e66d4537SJon Lin
rkusb_do_vs_write(struct fsg_common * common)4590d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common)
4600d0c3248SFrank Wang {
4610d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun];
4620d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]);
4630d0c3248SFrank Wang struct vendor_item *vhead;
4640d0c3248SFrank Wang struct fsg_buffhd *bh;
4650d0c3248SFrank Wang void *data;
4660d0c3248SFrank Wang int rc;
4670d0c3248SFrank Wang
4680d0c3248SFrank Wang if (common->data_size >= (u32)65536) {
4690d0c3248SFrank Wang /* _MUST_ small than 64K */
4700d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
4710d0c3248SFrank Wang return -EINVAL;
4720d0c3248SFrank Wang }
4730d0c3248SFrank Wang
4740d0c3248SFrank Wang common->residue = common->data_size;
4750d0c3248SFrank Wang common->usb_amount_left = common->data_size;
4760d0c3248SFrank Wang
4770d0c3248SFrank Wang /* Carry out the file writes */
4780d0c3248SFrank Wang if (unlikely(common->data_size == 0))
4790d0c3248SFrank Wang return -EIO; /* No data to write */
4800d0c3248SFrank Wang
4810d0c3248SFrank Wang for (;;) {
4820d0c3248SFrank Wang if (common->usb_amount_left > 0) {
4830d0c3248SFrank Wang /* Wait for the next buffer to become available */
4840d0c3248SFrank Wang bh = common->next_buffhd_to_fill;
4850d0c3248SFrank Wang if (bh->state != BUF_STATE_EMPTY)
4860d0c3248SFrank Wang goto wait;
4870d0c3248SFrank Wang
4880d0c3248SFrank Wang /* Request the next buffer */
4890d0c3248SFrank Wang common->usb_amount_left -= common->data_size;
4900d0c3248SFrank Wang bh->outreq->length = common->data_size;
4910d0c3248SFrank Wang bh->bulk_out_intended_length = common->data_size;
4920d0c3248SFrank Wang bh->outreq->short_not_ok = 1;
4930d0c3248SFrank Wang
4940d0c3248SFrank Wang START_TRANSFER_OR(common, bulk_out, bh->outreq,
4950d0c3248SFrank Wang &bh->outreq_busy, &bh->state)
4960d0c3248SFrank Wang /*
4970d0c3248SFrank Wang * Don't know what to do if
4980d0c3248SFrank Wang * common->fsg is NULL
4990d0c3248SFrank Wang */
5000d0c3248SFrank Wang return -EIO;
5010d0c3248SFrank Wang common->next_buffhd_to_fill = bh->next;
5020d0c3248SFrank Wang } else {
5030d0c3248SFrank Wang /* Then, wait for the data to become available */
5040d0c3248SFrank Wang bh = common->next_buffhd_to_drain;
5050d0c3248SFrank Wang if (bh->state != BUF_STATE_FULL)
5060d0c3248SFrank Wang goto wait;
5070d0c3248SFrank Wang
5080d0c3248SFrank Wang common->next_buffhd_to_drain = bh->next;
5090d0c3248SFrank Wang bh->state = BUF_STATE_EMPTY;
5100d0c3248SFrank Wang
5110d0c3248SFrank Wang /* Did something go wrong with the transfer? */
5120d0c3248SFrank Wang if (bh->outreq->status != 0) {
5130d0c3248SFrank Wang curlun->sense_data = SS_COMMUNICATION_FAILURE;
5140d0c3248SFrank Wang curlun->info_valid = 1;
5150d0c3248SFrank Wang break;
5160d0c3248SFrank Wang }
5170d0c3248SFrank Wang
5180d0c3248SFrank Wang /* Perform the write */
5190d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf;
5200d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item);
52173eced63SXuhui Lin if (CONFIG_IS_ENABLED(ROCKCHIP_VENDOR_PARTITION) && !type) {
52270990948SYifeng Zhao #ifndef CONFIG_SUPPORT_USBPLUG
523420ee9d5SJoseph Chen if (vhead->id == HDCP_14_HDMI_ID ||
52478dcc928SZhang Yubing vhead->id == HDCP_14_HDMIRX_ID ||
52578dcc928SZhang Yubing vhead->id == HDCP_14_DP_ID) {
526420ee9d5SJoseph Chen rc = vendor_handle_hdcp(vhead);
527420ee9d5SJoseph Chen if (rc < 0) {
528420ee9d5SJoseph Chen curlun->sense_data = SS_WRITE_ERROR;
529420ee9d5SJoseph Chen return -EIO;
530420ee9d5SJoseph Chen }
531420ee9d5SJoseph Chen }
53270990948SYifeng Zhao #endif
533420ee9d5SJoseph Chen
5340d0c3248SFrank Wang /* Vendor storage */
5350d0c3248SFrank Wang rc = vendor_storage_write(vhead->id,
5360d0c3248SFrank Wang (char __user *)data,
5370d0c3248SFrank Wang vhead->size);
53819652be0SFrank Wang if (rc < 0) {
53919652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR;
5400d0c3248SFrank Wang return -EIO;
54119652be0SFrank Wang }
5422122174dSWu Liangqing } else if (type == 1) {
5430d0c3248SFrank Wang /* RPMB */
5446f0347c8Stony.xu rc =
5456f0347c8Stony.xu write_keybox_to_secure_storage((u8 *)data,
5466f0347c8Stony.xu vhead->size);
54719652be0SFrank Wang if (rc < 0) {
54819652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR;
5496f0347c8Stony.xu return -EIO;
5500d0c3248SFrank Wang }
5512122174dSWu Liangqing } else if (type == 2) {
5522122174dSWu Liangqing /* security storage */
5532122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
5542122174dSWu Liangqing debug("%s call rk_avb_write_perm_attr %d, %d\n",
5552122174dSWu Liangqing __func__, vhead->id, vhead->size);
5562122174dSWu Liangqing rc = rk_avb_write_perm_attr(vhead->id,
5572122174dSWu Liangqing (char __user *)data,
5582122174dSWu Liangqing vhead->size);
5592122174dSWu Liangqing if (rc < 0) {
5602122174dSWu Liangqing curlun->sense_data = SS_WRITE_ERROR;
5612122174dSWu Liangqing return -EIO;
5622122174dSWu Liangqing }
5632122174dSWu Liangqing #else
5642122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER\n");
5652122174dSWu Liangqing #endif
566850ced9dSHisping Lin } else if (type == 3) {
567850ced9dSHisping Lin /* efuse or otp*/
568850ced9dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
569850ced9dSHisping Lin if (memcmp(data, "TAEK", 4) == 0) {
570850ced9dSHisping Lin if (vhead->size - 8 != 32) {
571850ced9dSHisping Lin printf("check ta encryption key size fail!\n");
572850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
573850ced9dSHisping Lin return -EIO;
574850ced9dSHisping Lin }
575850ced9dSHisping Lin if (trusty_write_ta_encryption_key((uint32_t *)(data + 8), 8) != 0) {
576850ced9dSHisping Lin printf("trusty_write_ta_encryption_key error!");
577850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
578850ced9dSHisping Lin return -EIO;
579850ced9dSHisping Lin }
580a43611afSHisping Lin } else if (memcmp(data, "EHUK", 4) == 0) {
581a43611afSHisping Lin if (vhead->size - 8 != 32) {
582a43611afSHisping Lin printf("check oem huk size fail!\n");
583a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
584a43611afSHisping Lin return -EIO;
585a43611afSHisping Lin }
586a43611afSHisping Lin if (trusty_write_oem_huk((uint32_t *)(data + 8), 8) != 0) {
587a43611afSHisping Lin printf("trusty_write_oem_huk error!");
588a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
589a43611afSHisping Lin return -EIO;
590a43611afSHisping Lin }
591005bd059SHisping Lin } else if (memcmp(data, "ENDA", 4) == 0) {
592005bd059SHisping Lin if (vhead->size - 8 != 16) {
593005bd059SHisping Lin printf("check oem encrypt data size fail!\n");
594005bd059SHisping Lin curlun->sense_data = SS_WRITE_ERROR;
595005bd059SHisping Lin return -EIO;
596005bd059SHisping Lin }
597005bd059SHisping Lin if (trusty_write_oem_encrypt_data((uint32_t *)(data + 8), 4) != 0) {
598005bd059SHisping Lin printf("trusty_write_oem_encrypt_data error!");
599005bd059SHisping Lin curlun->sense_data = SS_WRITE_ERROR;
600005bd059SHisping Lin return -EIO;
601005bd059SHisping Lin }
6021dd9b2ceSHisping Lin } else if (memcmp(data, "OTPK", 4) == 0) {
6031dd9b2ceSHisping Lin uint32_t key_len = vhead->size - 9;
6041dd9b2ceSHisping Lin uint8_t key_id = *((uint8_t *)data + 8);
605d049485dSHisping Lin if (key_len == 4 && memcmp(data + 9, "lock", 4) == 0) {
606d049485dSHisping Lin if (trusty_set_oem_hr_otp_read_lock(key_id) != 0) {
607d049485dSHisping Lin printf("trusty_set_oem_hr_otp_read_lock error!");
608d049485dSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
609d049485dSHisping Lin return -EIO;
610d049485dSHisping Lin }
611d049485dSHisping Lin } else {
6121dd9b2ceSHisping Lin if (key_len != 16 && key_len != 24 && key_len != 32) {
6131dd9b2ceSHisping Lin printf("check oem otp key size fail!\n");
6141dd9b2ceSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
6151dd9b2ceSHisping Lin return -EIO;
6161dd9b2ceSHisping Lin }
6171dd9b2ceSHisping Lin if (trusty_write_oem_otp_key(key_id, (uint8_t *)(data + 9), key_len) != 0) {
618d049485dSHisping Lin printf("trusty_write_oem_otp_key error!");
6191dd9b2ceSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
6201dd9b2ceSHisping Lin return -EIO;
6211dd9b2ceSHisping Lin }
622d049485dSHisping Lin }
62304569280SHisping Lin } else if (memcmp(data, "FWEK", 4) == 0) {
62404569280SHisping Lin uint32_t key_len = vhead->size - 9;
62504569280SHisping Lin uint8_t key_id = *((uint8_t *)data + 8);
62604569280SHisping Lin if (key_len == 4 && memcmp(data + 9, "lock", 4) == 0) {
62704569280SHisping Lin if (trusty_set_fw_encrypt_key_mask(key_id) != 0) {
62804569280SHisping Lin printf("trusty_set_fw_encrypt_key_mask error!");
62904569280SHisping Lin curlun->sense_data = SS_WRITE_ERROR;
63004569280SHisping Lin return -EIO;
63104569280SHisping Lin }
63204569280SHisping Lin } else {
63304569280SHisping Lin if (key_len != 16 && key_len != 32) {
63404569280SHisping Lin printf("check FW encrypt key size fail!\n");
63504569280SHisping Lin curlun->sense_data = SS_WRITE_ERROR;
63604569280SHisping Lin return -EIO;
63704569280SHisping Lin }
63804569280SHisping Lin if (trusty_write_fw_encrypt_key(key_id, (uint8_t *)(data + 9), key_len) != 0) {
63904569280SHisping Lin printf("trusty_write_fw_encrypt_key error!");
64004569280SHisping Lin curlun->sense_data = SS_WRITE_ERROR;
64104569280SHisping Lin return -EIO;
64204569280SHisping Lin }
64304569280SHisping Lin }
644850ced9dSHisping Lin } else {
645850ced9dSHisping Lin printf("Unknown tag\n");
646850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR;
647850ced9dSHisping Lin return -EIO;
648850ced9dSHisping Lin }
649850ced9dSHisping Lin #else
650850ced9dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n");
651850ced9dSHisping Lin #endif
6522122174dSWu Liangqing } else {
6532122174dSWu Liangqing return -EINVAL;
65419652be0SFrank Wang }
6550d0c3248SFrank Wang
6560d0c3248SFrank Wang common->residue -= common->data_size;
6570d0c3248SFrank Wang
6580d0c3248SFrank Wang /* Did the host decide to stop early? */
6590d0c3248SFrank Wang if (bh->outreq->actual != bh->outreq->length)
6600d0c3248SFrank Wang common->short_packet_received = 1;
6610d0c3248SFrank Wang break; /* Command done */
6620d0c3248SFrank Wang }
6630d0c3248SFrank Wang wait:
6640d0c3248SFrank Wang /* Wait for something to happen */
6650d0c3248SFrank Wang rc = sleep_thread(common);
6660d0c3248SFrank Wang if (rc)
6670d0c3248SFrank Wang return rc;
6680d0c3248SFrank Wang }
6690d0c3248SFrank Wang
6700d0c3248SFrank Wang return -EIO; /* No default reply */
6710d0c3248SFrank Wang }
6720d0c3248SFrank Wang
rkusb_do_vs_read(struct fsg_common * common)6730d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common)
6740d0c3248SFrank Wang {
6750d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun];
6760d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]);
6770d0c3248SFrank Wang struct vendor_item *vhead;
6780d0c3248SFrank Wang struct fsg_buffhd *bh;
6790d0c3248SFrank Wang void *data;
6800d0c3248SFrank Wang int rc;
6810d0c3248SFrank Wang
6820d0c3248SFrank Wang if (common->data_size >= (u32)65536) {
6830d0c3248SFrank Wang /* _MUST_ small than 64K */
6840d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
6850d0c3248SFrank Wang return -EINVAL;
6860d0c3248SFrank Wang }
6870d0c3248SFrank Wang
6880d0c3248SFrank Wang common->residue = common->data_size;
6890d0c3248SFrank Wang common->usb_amount_left = common->data_size;
6900d0c3248SFrank Wang
6910d0c3248SFrank Wang /* Carry out the file reads */
6920d0c3248SFrank Wang if (unlikely(common->data_size == 0))
6930d0c3248SFrank Wang return -EIO; /* No default reply */
6940d0c3248SFrank Wang
6950d0c3248SFrank Wang for (;;) {
6960d0c3248SFrank Wang /* Wait for the next buffer to become available */
6970d0c3248SFrank Wang bh = common->next_buffhd_to_fill;
6980d0c3248SFrank Wang while (bh->state != BUF_STATE_EMPTY) {
6990d0c3248SFrank Wang rc = sleep_thread(common);
7000d0c3248SFrank Wang if (rc)
7010d0c3248SFrank Wang return rc;
7020d0c3248SFrank Wang }
7030d0c3248SFrank Wang
7040d0c3248SFrank Wang memset(bh->buf, 0, FSG_BUFLEN);
7050d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf;
7060d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item);
7070d0c3248SFrank Wang vhead->id = get_unaligned_be16(&common->cmnd[2]);
70873eced63SXuhui Lin if (CONFIG_IS_ENABLED(ROCKCHIP_VENDOR_PARTITION) && !type) {
7090d0c3248SFrank Wang /* Vendor storage */
7100d0c3248SFrank Wang rc = vendor_storage_read(vhead->id,
7110d0c3248SFrank Wang (char __user *)data,
7120d0c3248SFrank Wang common->data_size);
71319652be0SFrank Wang if (!rc) {
71419652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
7150d0c3248SFrank Wang return -EIO;
71619652be0SFrank Wang }
7170d0c3248SFrank Wang vhead->size = rc;
7182122174dSWu Liangqing } else if (type == 1) {
7190d0c3248SFrank Wang /* RPMB */
720700a3668STony Xu rc =
721700a3668STony Xu read_raw_data_from_secure_storage((u8 *)data,
722700a3668STony Xu common->data_size);
72319652be0SFrank Wang if (!rc) {
72419652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
725700a3668STony Xu return -EIO;
72619652be0SFrank Wang }
727700a3668STony Xu vhead->size = rc;
7282122174dSWu Liangqing } else if (type == 2) {
7292122174dSWu Liangqing /* security storage */
7302122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER
7312122174dSWu Liangqing rc = rk_avb_read_perm_attr(vhead->id,
7322122174dSWu Liangqing (char __user *)data,
7332122174dSWu Liangqing vhead->size);
7342122174dSWu Liangqing if (rc < 0)
7352122174dSWu Liangqing return -EIO;
7362122174dSWu Liangqing vhead->size = rc;
7372122174dSWu Liangqing #else
7382122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n");
7392122174dSWu Liangqing #endif
74047c8f13dSHisping Lin } else if (type == 3) {
74147c8f13dSHisping Lin /* efuse or otp*/
74247c8f13dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT
74347c8f13dSHisping Lin if (vhead->id == 120) {
74447c8f13dSHisping Lin u8 value;
74547c8f13dSHisping Lin char *written_str = "key is written!";
74647c8f13dSHisping Lin char *not_written_str = "key is not written!";
74747c8f13dSHisping Lin if (trusty_ta_encryption_key_is_written(&value) != 0) {
74847c8f13dSHisping Lin printf("trusty_ta_encryption_key_is_written error!");
74947c8f13dSHisping Lin return -EIO;
75047c8f13dSHisping Lin }
75147c8f13dSHisping Lin if (value) {
75247c8f13dSHisping Lin memcpy(data, written_str, strlen(written_str));
75347c8f13dSHisping Lin vhead->size = strlen(written_str);
75447c8f13dSHisping Lin } else {
75547c8f13dSHisping Lin memcpy(data, not_written_str, strlen(not_written_str));
75647c8f13dSHisping Lin vhead->size = strlen(not_written_str);
75747c8f13dSHisping Lin }
75847c8f13dSHisping Lin } else {
75947c8f13dSHisping Lin printf("Unknown tag\n");
76047c8f13dSHisping Lin return -EIO;
76147c8f13dSHisping Lin }
76247c8f13dSHisping Lin #else
76347c8f13dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n");
76447c8f13dSHisping Lin #endif
7652122174dSWu Liangqing } else {
7662122174dSWu Liangqing return -EINVAL;
7670d0c3248SFrank Wang }
7680d0c3248SFrank Wang
7690d0c3248SFrank Wang common->residue -= common->data_size;
7700d0c3248SFrank Wang bh->inreq->length = common->data_size;
7710d0c3248SFrank Wang bh->state = BUF_STATE_FULL;
7720d0c3248SFrank Wang
7730d0c3248SFrank Wang break; /* No more left to read */
7740d0c3248SFrank Wang }
7750d0c3248SFrank Wang
7760d0c3248SFrank Wang return -EIO; /* No default reply */
7770d0c3248SFrank Wang }
7780d0c3248SFrank Wang
7794428ea84SYifeng Zhao #if CONFIG_PSTORE
rkusb_do_uart_debug_read(struct fsg_common * common)7804428ea84SYifeng Zhao static int rkusb_do_uart_debug_read(struct fsg_common *common)
7814428ea84SYifeng Zhao {
7824428ea84SYifeng Zhao struct fsg_buffhd *bh;
7834428ea84SYifeng Zhao int *debug_head;
7844428ea84SYifeng Zhao int debug_data_size;
7854428ea84SYifeng Zhao int rc;
7864428ea84SYifeng Zhao
7874428ea84SYifeng Zhao if (common->data_size >= (u32)FSG_BUFLEN)
7884428ea84SYifeng Zhao return -EINVAL;
7894428ea84SYifeng Zhao
7904428ea84SYifeng Zhao common->residue = common->data_size;
7914428ea84SYifeng Zhao common->usb_amount_left = common->data_size;
7924428ea84SYifeng Zhao
7934428ea84SYifeng Zhao /* Carry out the file reads */
7944428ea84SYifeng Zhao if (unlikely(common->data_size == 0) || unlikely(!gd->pstore_addr))
7954428ea84SYifeng Zhao return -EIO; /* No default reply */
7964428ea84SYifeng Zhao
7974428ea84SYifeng Zhao /* Wait for the next buffer to become available */
7984428ea84SYifeng Zhao bh = common->next_buffhd_to_fill;
7994428ea84SYifeng Zhao while (bh->state != BUF_STATE_EMPTY) {
8004428ea84SYifeng Zhao rc = sleep_thread(common);
8014428ea84SYifeng Zhao if (rc)
8024428ea84SYifeng Zhao return rc;
8034428ea84SYifeng Zhao }
8044428ea84SYifeng Zhao
8054428ea84SYifeng Zhao debug_head = (int *)gd->pstore_addr;
8064428ea84SYifeng Zhao debug_data_size = debug_head[2];
8074428ea84SYifeng Zhao if (debug_data_size > FSG_BUFLEN - 8)
8084428ea84SYifeng Zhao debug_data_size = FSG_BUFLEN - 8;
8094428ea84SYifeng Zhao if (debug_data_size > common->data_size - 8)
8104428ea84SYifeng Zhao debug_data_size = common->data_size - 8;
8114428ea84SYifeng Zhao
8124428ea84SYifeng Zhao debug_head = (int *)bh->buf;
8134428ea84SYifeng Zhao debug_head[0] = 0x55424544;
8144428ea84SYifeng Zhao debug_head[1] = debug_data_size + 8;
8154428ea84SYifeng Zhao
8164428ea84SYifeng Zhao memcpy((void *)(bh->buf + 8), (void *)(gd->pstore_addr + 12), debug_data_size);
8174428ea84SYifeng Zhao
8184428ea84SYifeng Zhao common->residue -= common->data_size;
8194428ea84SYifeng Zhao bh->inreq->length = common->data_size;
8204428ea84SYifeng Zhao bh->state = BUF_STATE_FULL;
8214428ea84SYifeng Zhao
8224428ea84SYifeng Zhao return -EIO; /* No default reply */
8234428ea84SYifeng Zhao }
8244428ea84SYifeng Zhao #endif
8254428ea84SYifeng Zhao
rkusb_do_switch_storage(struct fsg_common * common)8264d2787f5SJon Lin static int rkusb_do_switch_storage(struct fsg_common *common)
8274d2787f5SJon Lin {
8284d2787f5SJon Lin enum if_type type, cur_type = ums[common->lun].block_dev.if_type;
8294d2787f5SJon Lin int devnum, cur_devnum = ums[common->lun].block_dev.devnum;
8304d2787f5SJon Lin struct blk_desc *block_dev;
8314d2787f5SJon Lin u32 media = BOOT_TYPE_UNKNOWN;
8324d2787f5SJon Lin
8334d2787f5SJon Lin media = 1 << common->cmnd[1];
8344d2787f5SJon Lin
8354d2787f5SJon Lin switch (media) {
83622c2f449SJon Lin #ifdef CONFIG_MMC
8374d2787f5SJon Lin case BOOT_TYPE_EMMC:
8384d2787f5SJon Lin type = IF_TYPE_MMC;
8394d2787f5SJon Lin devnum = 0;
8404d2787f5SJon Lin mmc_initialize(gd->bd);
8414d2787f5SJon Lin break;
84222c2f449SJon Lin #endif
8434d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_NAND:
8444d2787f5SJon Lin type = IF_TYPE_MTD;
8454d2787f5SJon Lin devnum = 0;
8464d2787f5SJon Lin break;
8474d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_SPI_NAND:
8484d2787f5SJon Lin type = IF_TYPE_MTD;
8494d2787f5SJon Lin devnum = 1;
8504d2787f5SJon Lin break;
8514d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_SPI_NOR:
8524d2787f5SJon Lin type = IF_TYPE_MTD;
8534d2787f5SJon Lin devnum = 2;
8544d2787f5SJon Lin break;
8551b375c35SYifeng Zhao #if defined(CONFIG_SCSI) && defined(CONFIG_CMD_SCSI) && (defined(CONFIG_AHCI) || defined(CONFIG_UFS))
8561b375c35SYifeng Zhao case BOOT_TYPE_SATA:
8571b375c35SYifeng Zhao type = IF_TYPE_SCSI;
8581b375c35SYifeng Zhao devnum = 0;
85992eae861SYifeng Zhao scsi_scan(true);
8601b375c35SYifeng Zhao break;
8611b375c35SYifeng Zhao #endif
862e0bae237SJon Lin case BOOT_TYPE_PCIE:
863e0bae237SJon Lin type = IF_TYPE_NVME;
864e0bae237SJon Lin devnum = 0;
865e0bae237SJon Lin break;
8664d2787f5SJon Lin default:
8674d2787f5SJon Lin printf("Bootdev 0x%x is not support\n", media);
8684d2787f5SJon Lin return -ENODEV;
8694d2787f5SJon Lin }
8704d2787f5SJon Lin
8714d2787f5SJon Lin if (cur_type == type && cur_devnum == devnum)
8724d2787f5SJon Lin return 0;
8734d2787f5SJon Lin
8748c6654f1SJon Lin #if CONFIG_IS_ENABLED(SUPPORT_USBPLUG)
8758c6654f1SJon Lin block_dev = usbplug_blk_get_devnum_by_type(type, devnum);
8768c6654f1SJon Lin #else
8774d2787f5SJon Lin block_dev = blk_get_devnum_by_type(type, devnum);
8788c6654f1SJon Lin #endif
8794d2787f5SJon Lin if (!block_dev) {
8804d2787f5SJon Lin printf("Bootdev if_type=%d num=%d toggle fail\n", type, devnum);
8814d2787f5SJon Lin return -ENODEV;
8824d2787f5SJon Lin }
8834d2787f5SJon Lin
884a1b07e70SYifeng Zhao common->luns[common->lun].num_sectors = block_dev->lba;
8854d2787f5SJon Lin ums[common->lun].num_sectors = block_dev->lba;
8864d2787f5SJon Lin ums[common->lun].block_dev = *block_dev;
8874d2787f5SJon Lin
8884d2787f5SJon Lin printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n",
8894d2787f5SJon Lin 0,
8904d2787f5SJon Lin ums[common->lun].block_dev.devnum,
8914d2787f5SJon Lin ums[common->lun].block_dev.hwpart,
8924d2787f5SJon Lin ums[common->lun].start_sector,
8934d2787f5SJon Lin ums[common->lun].num_sectors);
8944d2787f5SJon Lin
8954d2787f5SJon Lin return 0;
8964d2787f5SJon Lin }
8974d2787f5SJon Lin
rkusb_do_get_storage_info(struct fsg_common * common,struct fsg_buffhd * bh)898d4cce25eSYifeng Zhao static int rkusb_do_get_storage_info(struct fsg_common *common,
899d4cce25eSYifeng Zhao struct fsg_buffhd *bh)
900d4cce25eSYifeng Zhao {
901d4cce25eSYifeng Zhao enum if_type type = ums[common->lun].block_dev.if_type;
902d4cce25eSYifeng Zhao int devnum = ums[common->lun].block_dev.devnum;
903d4cce25eSYifeng Zhao u32 media = BOOT_TYPE_UNKNOWN;
904d4cce25eSYifeng Zhao u32 len = common->data_size;
905d4cce25eSYifeng Zhao u8 *buf = (u8 *)bh->buf;
906d4cce25eSYifeng Zhao
907d4cce25eSYifeng Zhao if (len > 4)
908d4cce25eSYifeng Zhao len = 4;
909d4cce25eSYifeng Zhao
910d4cce25eSYifeng Zhao switch (type) {
911d4cce25eSYifeng Zhao case IF_TYPE_MMC:
912d4cce25eSYifeng Zhao media = BOOT_TYPE_EMMC;
913d4cce25eSYifeng Zhao break;
914d4cce25eSYifeng Zhao
915d4cce25eSYifeng Zhao case IF_TYPE_SD:
916d4cce25eSYifeng Zhao media = BOOT_TYPE_SD0;
917d4cce25eSYifeng Zhao break;
918d4cce25eSYifeng Zhao
919d4cce25eSYifeng Zhao case IF_TYPE_MTD:
920d4cce25eSYifeng Zhao if (devnum == BLK_MTD_SPI_NAND)
921d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NAND;
922d4cce25eSYifeng Zhao else if (devnum == BLK_MTD_NAND)
923d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND;
924d4cce25eSYifeng Zhao else
925d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NOR;
926d4cce25eSYifeng Zhao break;
927d4cce25eSYifeng Zhao
928d4cce25eSYifeng Zhao case IF_TYPE_SCSI:
929d4cce25eSYifeng Zhao media = BOOT_TYPE_SATA;
930d4cce25eSYifeng Zhao break;
931d4cce25eSYifeng Zhao
932d4cce25eSYifeng Zhao case IF_TYPE_RKNAND:
933d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND;
934d4cce25eSYifeng Zhao break;
9352daa60eeSJon Lin
9362daa60eeSJon Lin case IF_TYPE_NVME:
9372daa60eeSJon Lin media = BOOT_TYPE_PCIE;
9382daa60eeSJon Lin break;
9392daa60eeSJon Lin
940d4cce25eSYifeng Zhao default:
941d4cce25eSYifeng Zhao break;
942d4cce25eSYifeng Zhao }
943d4cce25eSYifeng Zhao
944d4cce25eSYifeng Zhao memcpy((void *)&buf[0], (void *)&media, len);
945d4cce25eSYifeng Zhao common->residue = len;
946d4cce25eSYifeng Zhao common->data_size_from_cmnd = len;
947d4cce25eSYifeng Zhao
948d4cce25eSYifeng Zhao return len;
949d4cce25eSYifeng Zhao }
950d4cce25eSYifeng Zhao
rkusb_do_read_capacity(struct fsg_common * common,struct fsg_buffhd * bh)951f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common,
952f16e43f8SFrank Wang struct fsg_buffhd *bh)
953f16e43f8SFrank Wang {
954f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf;
955f16e43f8SFrank Wang u32 len = common->data_size;
956d015bf41SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type;
957e66d4537SJon Lin int devnum = ums[common->lun].block_dev.devnum;
958f16e43f8SFrank Wang
959f16e43f8SFrank Wang /*
960f16e43f8SFrank Wang * bit[0]: Direct LBA, 0: Disabled;
9610d0c3248SFrank Wang * bit[1]: Vendor Storage API, 0: Disabed (default);
962d015bf41SFrank Wang * bit[2]: First 4M Access, 0: Disabled;
9630d0c3248SFrank Wang * bit[3]: Read LBA On, 0: Disabed (default);
9640d0c3248SFrank Wang * bit[4]: New Vendor Storage API, 0: Disabed;
965d4cce25eSYifeng Zhao * bit[5]: Read uart data from ram
966d4cce25eSYifeng Zhao * bit[6]: Read IDB config
967d4cce25eSYifeng Zhao * bit[7]: Read SecureMode
968d4cce25eSYifeng Zhao * bit[8]: New IDB feature
969d4cce25eSYifeng Zhao * bit[9]: Get storage media info
9708168f857SYifeng Zhao * bit[10]: LBAwrite Parity
9718168f857SYifeng Zhao * bit[11]: Read Otp Data
9728168f857SYifeng Zhao * bit[12]: usb3 download
9738168f857SYifeng Zhao * bit[13]: Write OTP proof
9748168f857SYifeng Zhao * bit[14]: Write Cipher Key
9758168f857SYifeng Zhao * bit[15:63}: Reserved.
976f16e43f8SFrank Wang */
977f16e43f8SFrank Wang memset((void *)&buf[0], 0, len);
9782daa60eeSJon Lin if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME)
9790d0c3248SFrank Wang buf[0] = BIT(0) | BIT(2) | BIT(4);
9800d0c3248SFrank Wang else
9810d0c3248SFrank Wang buf[0] = BIT(0) | BIT(4);
982f16e43f8SFrank Wang
983e66d4537SJon Lin if (type == IF_TYPE_MTD &&
984e66d4537SJon Lin (devnum == BLK_MTD_NAND ||
985e66d4537SJon Lin devnum == BLK_MTD_SPI_NAND))
986e66d4537SJon Lin buf[0] |= (1 << 6);
987e66d4537SJon Lin
9884428ea84SYifeng Zhao #ifdef CONFIG_PSTORE
9894428ea84SYifeng Zhao buf[0] |= (1 << 5);
9904428ea84SYifeng Zhao #endif
9914428ea84SYifeng Zhao
992398ff6a5SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126)
99365a0fed9SJon Lin if (type == IF_TYPE_MTD && devnum == BLK_MTD_SPI_NOR)
99465a0fed9SJon Lin buf[0] |= (1 << 6);
995398ff6a5SJon Lin #if defined(CONFIG_ROCKCHIP_RK3308)
996398ff6a5SJon Lin else if (type == IF_TYPE_SPINOR)
997398ff6a5SJon Lin buf[0] |= (1 << 6);
998398ff6a5SJon Lin #endif
99965a0fed9SJon Lin #endif
100065a0fed9SJon Lin
10010b97a2cbSJoseph Chen #if defined(CONFIG_ROCKCHIP_NEW_IDB)
1002007849d8SYifeng Zhao buf[1] = BIT(0);
1003007849d8SYifeng Zhao #endif
10042c0c66c1SYifeng Zhao buf[1] |= BIT(1); /* Switch Storage */
10052c0c66c1SYifeng Zhao buf[1] |= BIT(2); /* LBAwrite Parity */
1006d4cce25eSYifeng Zhao
100736c87911Swilliam.wu if (rkusb_usb3_capable() && !rkusb_force_usb2_enabled())
10083c7547fcSWilliam Wu buf[1] |= BIT(4);
100936c87911Swilliam.wu else
10103c7547fcSWilliam Wu buf[1] &= ~BIT(4);
101136c87911Swilliam.wu
10128168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP
10138168f857SYifeng Zhao buf[1] |= BIT(3); /* Read Otp Data */
10148168f857SYifeng Zhao buf[1] |= BIT(5); /* Write OTP proof */
10158168f857SYifeng Zhao buf[1] |= BIT(6); /* Write Cipher Key */
10168168f857SYifeng Zhao #endif
10178168f857SYifeng Zhao
1018f16e43f8SFrank Wang /* Set data xfer size */
1019e66d4537SJon Lin common->residue = len;
1020e66d4537SJon Lin common->data_size_from_cmnd = len;
1021f16e43f8SFrank Wang
1022f16e43f8SFrank Wang return len;
1023f16e43f8SFrank Wang }
1024f16e43f8SFrank Wang
10258168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP
rkusb_do_read_otp(struct fsg_common * common,struct fsg_buffhd * bh)10268168f857SYifeng Zhao static int rkusb_do_read_otp(struct fsg_common *common,
10278168f857SYifeng Zhao struct fsg_buffhd *bh)
10288168f857SYifeng Zhao {
10298168f857SYifeng Zhao u32 len = common->data_size;
10308168f857SYifeng Zhao u32 type = common->cmnd[1];
10318168f857SYifeng Zhao u8 *buf = (u8 *)bh->buf;
10328168f857SYifeng Zhao struct udevice *dev;
10338168f857SYifeng Zhao
10348168f857SYifeng Zhao buf[0] = 0;
10358168f857SYifeng Zhao if (type == 0) { /* soc uuid */
10368168f857SYifeng Zhao if (!uclass_get_device_by_driver(UCLASS_MISC, DM_GET_DRIVER(rockchip_otp), &dev)) {
10378168f857SYifeng Zhao if (!misc_read(dev, CFG_CPUID_OFFSET, (void *)&buf[1], len))
10388168f857SYifeng Zhao buf[0] = len;
10398168f857SYifeng Zhao }
10408168f857SYifeng Zhao }
10418168f857SYifeng Zhao
10428168f857SYifeng Zhao common->residue = len;
10438168f857SYifeng Zhao common->data_size_from_cmnd = len;
10448168f857SYifeng Zhao
10458168f857SYifeng Zhao return len;
10468168f857SYifeng Zhao }
10478168f857SYifeng Zhao #endif
10488168f857SYifeng Zhao
rkusb_fixup_cbwcb(struct fsg_common * common,struct fsg_buffhd * bh)1049d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common,
1050d23ec8c4SKever Yang struct fsg_buffhd *bh)
1051d23ec8c4SKever Yang {
1052d23ec8c4SKever Yang struct usb_request *req = bh->outreq;
1053d23ec8c4SKever Yang struct fsg_bulk_cb_wrap *cbw = req->buf;
1054d23ec8c4SKever Yang
1055d23ec8c4SKever Yang /* FIXME cbw.DataTransferLength was not set by Upgrade Tool */
1056d23ec8c4SKever Yang common->data_size = le32_to_cpu(cbw->DataTransferLength);
1057d23ec8c4SKever Yang if (common->data_size == 0) {
1058d23ec8c4SKever Yang common->data_size =
1059d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]) << 9;
1060d23ec8c4SKever Yang printf("Trasfer Length NOT set, please use new version tool\n");
1061d23ec8c4SKever Yang debug("%s %d, cmnd1 %x\n", __func__,
1062d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]),
1063d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[1]));
1064d23ec8c4SKever Yang }
1065d23ec8c4SKever Yang if (cbw->Flags & USB_BULK_IN_FLAG)
1066d23ec8c4SKever Yang common->data_dir = DATA_DIR_TO_HOST;
1067d23ec8c4SKever Yang else
1068d23ec8c4SKever Yang common->data_dir = DATA_DIR_FROM_HOST;
1069d23ec8c4SKever Yang
1070d23ec8c4SKever Yang /* Not support */
1071d23ec8c4SKever Yang common->cmnd[1] = 0;
1072d23ec8c4SKever Yang }
1073d23ec8c4SKever Yang
rkusb_cmd_process(struct fsg_common * common,struct fsg_buffhd * bh,int * reply)1074f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common,
1075f16e43f8SFrank Wang struct fsg_buffhd *bh, int *reply)
1076f16e43f8SFrank Wang {
1077f16e43f8SFrank Wang struct usb_request *req = bh->outreq;
1078f16e43f8SFrank Wang struct fsg_bulk_cb_wrap *cbw = req->buf;
1079f16e43f8SFrank Wang int rc;
1080f16e43f8SFrank Wang
1081f16e43f8SFrank Wang dump_cbw(cbw);
1082f16e43f8SFrank Wang
1083f16e43f8SFrank Wang if (rkusb_check_lun(common)) {
1084f16e43f8SFrank Wang *reply = -EINVAL;
1085f16e43f8SFrank Wang return RKUSB_RC_ERROR;
1086f16e43f8SFrank Wang }
1087f16e43f8SFrank Wang
1088f16e43f8SFrank Wang switch (common->cmnd[0]) {
1089f16e43f8SFrank Wang case RKUSB_TEST_UNIT_READY:
1090f16e43f8SFrank Wang *reply = rkusb_do_test_unit_ready(common, bh);
1091f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED;
1092f16e43f8SFrank Wang break;
1093f16e43f8SFrank Wang
1094f16e43f8SFrank Wang case RKUSB_READ_FLASH_ID:
1095f16e43f8SFrank Wang *reply = rkusb_do_read_flash_id(common, bh);
1096f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED;
1097f16e43f8SFrank Wang break;
1098f16e43f8SFrank Wang
1099f16e43f8SFrank Wang case RKUSB_TEST_BAD_BLOCK:
1100f16e43f8SFrank Wang *reply = rkusb_do_test_bad_block(common, bh);
1101f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED;
1102f16e43f8SFrank Wang break;
1103f16e43f8SFrank Wang
1104e66d4537SJon Lin case RKUSB_ERASE_10_FORCE:
1105e66d4537SJon Lin *reply = rkusb_do_erase_force(common, bh);
1106e66d4537SJon Lin rc = RKUSB_RC_FINISHED;
1107e66d4537SJon Lin break;
1108e66d4537SJon Lin
1109f16e43f8SFrank Wang case RKUSB_LBA_READ_10:
11105fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh);
1111f16e43f8SFrank Wang common->cmnd[0] = SC_READ_10;
1112f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */
1113f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE;
1114f16e43f8SFrank Wang break;
1115f16e43f8SFrank Wang
1116f16e43f8SFrank Wang case RKUSB_LBA_WRITE_10:
11175fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh);
1118f16e43f8SFrank Wang common->cmnd[0] = SC_WRITE_10;
1119f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */
1120f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE;
1121f16e43f8SFrank Wang break;
1122f16e43f8SFrank Wang
1123f16e43f8SFrank Wang case RKUSB_READ_FLASH_INFO:
1124f16e43f8SFrank Wang *reply = rkusb_do_read_flash_info(common, bh);
1125f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED;
1126f16e43f8SFrank Wang break;
1127f16e43f8SFrank Wang
1128829f2b85SFrank Wang case RKUSB_GET_CHIP_VER:
1129829f2b85SFrank Wang *reply = rkusb_do_get_chip_info(common, bh);
1130829f2b85SFrank Wang rc = RKUSB_RC_FINISHED;
1131829f2b85SFrank Wang break;
1132829f2b85SFrank Wang
1133f16e43f8SFrank Wang case RKUSB_LBA_ERASE:
1134f16e43f8SFrank Wang *reply = rkusb_do_lba_erase(common, bh);
1135f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED;
1136f16e43f8SFrank Wang break;
1137f16e43f8SFrank Wang
11380d0c3248SFrank Wang case RKUSB_VS_WRITE:
11390d0c3248SFrank Wang *reply = rkusb_do_vs_write(common);
11400d0c3248SFrank Wang rc = RKUSB_RC_FINISHED;
11410d0c3248SFrank Wang break;
11420d0c3248SFrank Wang
11430d0c3248SFrank Wang case RKUSB_VS_READ:
11440d0c3248SFrank Wang *reply = rkusb_do_vs_read(common);
11450d0c3248SFrank Wang rc = RKUSB_RC_FINISHED;
11460d0c3248SFrank Wang break;
114773eced63SXuhui Lin
11484428ea84SYifeng Zhao #ifdef CONFIG_PSTORE
11494428ea84SYifeng Zhao case RKUSB_UART_READ:
11504428ea84SYifeng Zhao rkusb_fixup_cbwcb(common, bh);
11514428ea84SYifeng Zhao *reply = rkusb_do_uart_debug_read(common);
11524428ea84SYifeng Zhao rc = RKUSB_RC_FINISHED;
11534428ea84SYifeng Zhao break;
11544428ea84SYifeng Zhao #endif
11554428ea84SYifeng Zhao
11564d2787f5SJon Lin case RKUSB_SWITCH_STORAGE:
11574d2787f5SJon Lin *reply = rkusb_do_switch_storage(common);
11584d2787f5SJon Lin rc = RKUSB_RC_FINISHED;
11594d2787f5SJon Lin break;
116073eced63SXuhui Lin
1161d4cce25eSYifeng Zhao case RKUSB_GET_STORAGE_MEDIA:
1162d4cce25eSYifeng Zhao *reply = rkusb_do_get_storage_info(common, bh);
1163d4cce25eSYifeng Zhao rc = RKUSB_RC_FINISHED;
1164d4cce25eSYifeng Zhao break;
11650d0c3248SFrank Wang
1166f16e43f8SFrank Wang case RKUSB_READ_CAPACITY:
1167f16e43f8SFrank Wang *reply = rkusb_do_read_capacity(common, bh);
1168f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED;
1169f16e43f8SFrank Wang break;
1170f16e43f8SFrank Wang
117136c87911Swilliam.wu case RKUSB_SWITCH_USB3:
117236c87911Swilliam.wu *reply = rkusb_do_switch_to_usb3(common, bh);
117336c87911Swilliam.wu rc = RKUSB_RC_FINISHED;
117436c87911Swilliam.wu break;
117536c87911Swilliam.wu
1176f16e43f8SFrank Wang case RKUSB_RESET:
1177f16e43f8SFrank Wang *reply = rkusb_do_reset(common, bh);
1178f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED;
1179f16e43f8SFrank Wang break;
1180f16e43f8SFrank Wang
11818168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP
11828168f857SYifeng Zhao case RKUSB_READ_OTP_DATA:
11838168f857SYifeng Zhao *reply = rkusb_do_read_otp(common, bh);
11848168f857SYifeng Zhao rc = RKUSB_RC_FINISHED;
11858168f857SYifeng Zhao break;
11868168f857SYifeng Zhao #endif
11878168f857SYifeng Zhao
1188f16e43f8SFrank Wang case RKUSB_READ_10:
1189f16e43f8SFrank Wang case RKUSB_WRITE_10:
1190e0023032SKever Yang printf("CMD Not support, pls use new version Tool\n");
1191e0023032SKever Yang case RKUSB_SET_DEVICE_ID:
1192f16e43f8SFrank Wang case RKUSB_ERASE_10:
1193f16e43f8SFrank Wang case RKUSB_WRITE_SPARE:
1194f16e43f8SFrank Wang case RKUSB_READ_SPARE:
1195f16e43f8SFrank Wang case RKUSB_GET_VERSION:
1196f16e43f8SFrank Wang case RKUSB_ERASE_SYS_DISK:
1197f16e43f8SFrank Wang case RKUSB_SDRAM_READ_10:
1198f16e43f8SFrank Wang case RKUSB_SDRAM_WRITE_10:
1199f16e43f8SFrank Wang case RKUSB_SDRAM_EXECUTE:
1200f16e43f8SFrank Wang case RKUSB_LOW_FORMAT:
1201f16e43f8SFrank Wang case RKUSB_SET_RESET_FLAG:
1202f16e43f8SFrank Wang case RKUSB_SPI_READ_10:
1203f16e43f8SFrank Wang case RKUSB_SPI_WRITE_10:
1204f16e43f8SFrank Wang /* Fall through */
1205f16e43f8SFrank Wang default:
1206f16e43f8SFrank Wang rc = RKUSB_RC_UNKNOWN_CMND;
1207f16e43f8SFrank Wang break;
1208f16e43f8SFrank Wang }
1209f16e43f8SFrank Wang
1210f16e43f8SFrank Wang return rc;
1211f16e43f8SFrank Wang }
1212f16e43f8SFrank Wang
rkusb_do_check_parity(struct fsg_common * common)12132c0c66c1SYifeng Zhao int rkusb_do_check_parity(struct fsg_common *common)
12142c0c66c1SYifeng Zhao {
12152c0c66c1SYifeng Zhao int ret = 0, rc;
12162c0c66c1SYifeng Zhao u32 parity, i, usb_parity, lba, len;
12172c0c66c1SYifeng Zhao static u32 usb_check_buffer[1024 * 256];
12182c0c66c1SYifeng Zhao
12192c0c66c1SYifeng Zhao usb_parity = common->cmnd[9] | (common->cmnd[10] << 8) |
12202c0c66c1SYifeng Zhao (common->cmnd[11] << 16) | (common->cmnd[12] << 24);
12212c0c66c1SYifeng Zhao
12222c0c66c1SYifeng Zhao if (common->cmnd[0] == SC_WRITE_10 && (usb_parity)) {
12232c0c66c1SYifeng Zhao lba = get_unaligned_be32(&common->cmnd[2]);
12242c0c66c1SYifeng Zhao len = common->data_size_from_cmnd >> 9;
12252c0c66c1SYifeng Zhao rc = blk_dread(&ums[common->lun].block_dev, lba, len, usb_check_buffer);
12262c0c66c1SYifeng Zhao parity = 0x000055aa;
12272c0c66c1SYifeng Zhao for (i = 0; i < len * 128; i++)
12282c0c66c1SYifeng Zhao parity += usb_check_buffer[i];
12292c0c66c1SYifeng Zhao if (!rc || parity != usb_parity)
12302c0c66c1SYifeng Zhao common->phase_error = 1;
12312c0c66c1SYifeng Zhao }
12322c0c66c1SYifeng Zhao
12332c0c66c1SYifeng Zhao return ret;
12342c0c66c1SYifeng Zhao }
12352c0c66c1SYifeng Zhao
1236f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add);
1237