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 240d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 250d0c3248SFrank Wang #include <asm/arch/vendor.h> 260d0c3248SFrank Wang #endif 27f16e43f8SFrank Wang #include <rockusb.h> 28f16e43f8SFrank Wang 29f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS 0xff 30f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS 0x06 31f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL 0x05 32f16e43f8SFrank Wang 33e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE 1024 34e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE 4 35e66d4537SJon Lin 36f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = { 37f16e43f8SFrank Wang .bLength = USB_DT_INTERFACE_SIZE, 38f16e43f8SFrank Wang .bDescriptorType = USB_DT_INTERFACE, 39f16e43f8SFrank Wang .bInterfaceNumber = 0x00, 40f16e43f8SFrank Wang .bAlternateSetting = 0x00, 41f16e43f8SFrank Wang .bNumEndpoints = 0x02, 42f16e43f8SFrank Wang .bInterfaceClass = ROCKUSB_INTERFACE_CLASS, 43f16e43f8SFrank Wang .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS, 44f16e43f8SFrank Wang .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL, 45f16e43f8SFrank Wang }; 46f16e43f8SFrank Wang 47f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = { 48f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc, 49f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_in_desc, 50f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_out_desc, 51f16e43f8SFrank Wang NULL, 52f16e43f8SFrank Wang }; 53f16e43f8SFrank Wang 54f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = { 55f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc, 56f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_in_desc, 57f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_out_desc, 58f16e43f8SFrank Wang NULL, 59f16e43f8SFrank Wang }; 60f16e43f8SFrank Wang 6126dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = { 6226dd3474SWilliam Wu (struct usb_descriptor_header *)&rkusb_intf_desc, 6326dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_desc, 6426dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc, 6526dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_desc, 6626dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc, 6726dd3474SWilliam Wu NULL, 6826dd3474SWilliam Wu }; 6926dd3474SWilliam Wu 70f16e43f8SFrank Wang struct rk_flash_info { 71f16e43f8SFrank Wang u32 flash_size; 72f16e43f8SFrank Wang u16 block_size; 73f16e43f8SFrank Wang u8 page_size; 74f16e43f8SFrank Wang u8 ecc_bits; 75f16e43f8SFrank Wang u8 access_time; 76f16e43f8SFrank Wang u8 manufacturer; 77f16e43f8SFrank Wang u8 flash_mask; 78f16e43f8SFrank Wang } __packed; 79f16e43f8SFrank Wang 805b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */ 815b081643SFrank Wang 82f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) 83f16e43f8SFrank Wang { 84ba437c8cSFrank Wang if (IS_RKUSB_UMS_DNL(name)) { 85c0acb0f2SFrank Wang /* Fix to Rockchip's VID and PID */ 86ba437c8cSFrank Wang dev->idVendor = __constant_cpu_to_le16(0x2207); 87ba437c8cSFrank Wang dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID); 88ba437c8cSFrank Wang 89f16e43f8SFrank Wang /* Enumerate as a loader device */ 9095424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG) 9195424692SJoseph Chen dev->bcdUSB = cpu_to_le16(0x0200); 9295424692SJoseph Chen #else 93f16e43f8SFrank Wang dev->bcdUSB = cpu_to_le16(0x0201); 9495424692SJoseph Chen #endif 95c0acb0f2SFrank Wang } else if (!strncmp(name, "usb_dnl_fastboot", 16)) { 96c0acb0f2SFrank Wang /* Fix to Google's VID and PID */ 97c0acb0f2SFrank Wang dev->idVendor = __constant_cpu_to_le16(0x18d1); 98c0acb0f2SFrank Wang dev->idProduct = __constant_cpu_to_le16(0xd00d); 99ca422507SYifeng Zhao } else if (!strncmp(name, "usb_dnl_dfu", 11)) { 100ca422507SYifeng Zhao /* Fix to Rockchip's VID and PID for DFU */ 101ca422507SYifeng Zhao dev->idVendor = cpu_to_le16(0x2207); 102ca422507SYifeng Zhao dev->idProduct = cpu_to_le16(0x0107); 1030a076251SFrank Wang } else if (!strncmp(name, "usb_dnl_ums", 11)) { 1040a076251SFrank Wang dev->idVendor = cpu_to_le16(0x2207); 1050a076251SFrank Wang dev->idProduct = cpu_to_le16(0x0010); 106ba437c8cSFrank Wang } 107f16e43f8SFrank Wang 108f16e43f8SFrank Wang return 0; 109f16e43f8SFrank Wang } 110f16e43f8SFrank Wang 111f16e43f8SFrank Wang __maybe_unused 112f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw) 113f16e43f8SFrank Wang { 114f16e43f8SFrank Wang assert(!cbw); 115f16e43f8SFrank Wang 116f16e43f8SFrank Wang debug("%s:\n", __func__); 117f16e43f8SFrank Wang debug("Signature %x\n", cbw->Signature); 118f16e43f8SFrank Wang debug("Tag %x\n", cbw->Tag); 119f16e43f8SFrank Wang debug("DataTransferLength %x\n", cbw->DataTransferLength); 120f16e43f8SFrank Wang debug("Flags %x\n", cbw->Flags); 121f16e43f8SFrank Wang debug("LUN %x\n", cbw->Lun); 122f16e43f8SFrank Wang debug("Length %x\n", cbw->Length); 123f16e43f8SFrank Wang debug("OptionCode %x\n", cbw->CDB[0]); 124f16e43f8SFrank Wang debug("SubCode %x\n", cbw->CDB[1]); 125f16e43f8SFrank Wang debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2])); 126f16e43f8SFrank Wang debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7])); 127f16e43f8SFrank Wang } 128f16e43f8SFrank Wang 129f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common) 130f16e43f8SFrank Wang { 131f16e43f8SFrank Wang struct fsg_lun *curlun; 132f16e43f8SFrank Wang 133f16e43f8SFrank Wang /* Check the LUN */ 134f16e43f8SFrank Wang if (common->lun >= 0 && common->lun < common->nluns) { 135f16e43f8SFrank Wang curlun = &common->luns[common->lun]; 136f16e43f8SFrank Wang if (common->cmnd[0] != SC_REQUEST_SENSE) { 137f16e43f8SFrank Wang curlun->sense_data = SS_NO_SENSE; 138f16e43f8SFrank Wang curlun->info_valid = 0; 139f16e43f8SFrank Wang } 140f16e43f8SFrank Wang } else { 141f16e43f8SFrank Wang curlun = NULL; 142f16e43f8SFrank Wang common->bad_lun_okay = 0; 143f16e43f8SFrank Wang 144f16e43f8SFrank Wang /* 145f16e43f8SFrank Wang * INQUIRY and REQUEST SENSE commands are explicitly allowed 146f16e43f8SFrank Wang * to use unsupported LUNs; all others may not. 147f16e43f8SFrank Wang */ 148f16e43f8SFrank Wang if (common->cmnd[0] != SC_INQUIRY && 149f16e43f8SFrank Wang common->cmnd[0] != SC_REQUEST_SENSE) { 150f16e43f8SFrank Wang debug("unsupported LUN %d\n", common->lun); 151f16e43f8SFrank Wang return -EINVAL; 152f16e43f8SFrank Wang } 153f16e43f8SFrank Wang } 154f16e43f8SFrank Wang 155f16e43f8SFrank Wang return 0; 156f16e43f8SFrank Wang } 157f16e43f8SFrank Wang 158f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req) 159f16e43f8SFrank Wang { 1605b081643SFrank Wang u32 boot_flag = BOOT_NORMAL; 1615b081643SFrank Wang 1625b081643SFrank Wang if (rkusb_rst_code == 0x03) 1635b081643SFrank Wang boot_flag = BOOT_BROM_DOWNLOAD; 1645b081643SFrank Wang 1655b081643SFrank Wang rkusb_rst_code = 0; /* restore to default */ 1665b081643SFrank Wang writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 167866d7966SJoseph Chen 168f16e43f8SFrank Wang do_reset(NULL, 0, 0, NULL); 169f16e43f8SFrank Wang } 170f16e43f8SFrank Wang 171f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common, 172f16e43f8SFrank Wang struct fsg_buffhd *bh) 173f16e43f8SFrank Wang { 174f16e43f8SFrank Wang common->data_size_from_cmnd = common->cmnd[4]; 175f16e43f8SFrank Wang common->residue = 0; 176f16e43f8SFrank Wang bh->inreq->complete = __do_reset; 177f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 178f16e43f8SFrank Wang 1795b081643SFrank Wang rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1]; 180f16e43f8SFrank Wang return 0; 181f16e43f8SFrank Wang } 182f16e43f8SFrank Wang 18336c87911Swilliam.wu __weak bool rkusb_usb3_capable(void) 18436c87911Swilliam.wu { 18536c87911Swilliam.wu return false; 18636c87911Swilliam.wu } 18736c87911Swilliam.wu 18836c87911Swilliam.wu static int rkusb_do_switch_to_usb3(struct fsg_common *common, 18936c87911Swilliam.wu struct fsg_buffhd *bh) 19036c87911Swilliam.wu { 19136c87911Swilliam.wu g_dnl_set_serialnumber((char *)&common->cmnd[1]); 19236c87911Swilliam.wu rkusb_switch_to_usb3_enable(true); 19336c87911Swilliam.wu bh->state = BUF_STATE_EMPTY; 19436c87911Swilliam.wu 19536c87911Swilliam.wu return 0; 19636c87911Swilliam.wu } 19736c87911Swilliam.wu 198f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common, 199f16e43f8SFrank Wang struct fsg_buffhd *bh) 200f16e43f8SFrank Wang { 2017eb64117SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 20218188f57SWilliam Wu u32 usb_trb_size; 20318188f57SWilliam Wu u16 residue; 2047eb64117SJon Lin 2057eb64117SJon Lin if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) || 2067eb64117SJon Lin desc->if_type == IF_TYPE_SPINOR) 20718188f57SWilliam Wu residue = 0x03; /* 128KB Max block xfer for SPI Nor */ 20818188f57SWilliam Wu else if (common->cmnd[1] == 0xf7 && FSG_BUFLEN >= 0x400000) 20918188f57SWilliam Wu residue = 0x0a; /* Max block xfer for USB DWC3 */ 2107eb64117SJon Lin else 21118188f57SWilliam Wu residue = 0x06; /* Max block xfer support from host */ 2127eb64117SJon Lin 21318188f57SWilliam Wu usb_trb_size = (1 << residue) * 4096; 21418188f57SWilliam Wu common->usb_trb_size = min(usb_trb_size, FSG_BUFLEN); 21518188f57SWilliam Wu common->residue = residue << 24; 216f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 217f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 218f16e43f8SFrank Wang 219f16e43f8SFrank Wang return 0; 220f16e43f8SFrank Wang } 221f16e43f8SFrank Wang 222f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common, 223f16e43f8SFrank Wang struct fsg_buffhd *bh) 224f16e43f8SFrank Wang { 225f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 226e0023032SKever Yang u32 len = 5; 227d7386f60SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 228afc6362aSJon Lin u32 devnum = ums[common->lun].block_dev.devnum; 229afc6362aSJon Lin const char *str; 230f16e43f8SFrank Wang 231afc6362aSJon Lin switch (type) { 232afc6362aSJon Lin case IF_TYPE_MMC: 233afc6362aSJon Lin str = "EMMC "; 234afc6362aSJon Lin break; 235afc6362aSJon Lin case IF_TYPE_RKNAND: 236afc6362aSJon Lin str = "NAND "; 237afc6362aSJon Lin break; 238afc6362aSJon Lin case IF_TYPE_MTD: 239afc6362aSJon Lin if (devnum == BLK_MTD_SPI_NAND) 240afc6362aSJon Lin str ="SNAND"; 241afc6362aSJon Lin else if (devnum == BLK_MTD_NAND) 242afc6362aSJon Lin str = "NAND "; 243d7386f60SFrank Wang else 244afc6362aSJon Lin str = "NOR "; 245afc6362aSJon Lin break; 246afc6362aSJon Lin default: 247afc6362aSJon Lin str = "UNKN "; /* unknown */ 248afc6362aSJon Lin break; 249afc6362aSJon Lin } 250afc6362aSJon Lin 251afc6362aSJon Lin memcpy((void *)&buf[0], str, len); 252f16e43f8SFrank Wang 253f16e43f8SFrank Wang /* Set data xfer size */ 254f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 255e0023032SKever Yang common->data_size = len; 256f16e43f8SFrank Wang 257f16e43f8SFrank Wang return len; 258f16e43f8SFrank Wang } 259f16e43f8SFrank Wang 260f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common, 261f16e43f8SFrank Wang struct fsg_buffhd *bh) 262f16e43f8SFrank Wang { 263f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 264e0023032SKever Yang u32 len = 64; 265f16e43f8SFrank Wang 266f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 267f16e43f8SFrank Wang 268f16e43f8SFrank Wang /* Set data xfer size */ 269f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 270e0023032SKever Yang common->data_size = len; 271f16e43f8SFrank Wang 272f16e43f8SFrank Wang return len; 273f16e43f8SFrank Wang } 274f16e43f8SFrank Wang 275f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common, 276f16e43f8SFrank Wang struct fsg_buffhd *bh) 277f16e43f8SFrank Wang { 278e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 279f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 280d23ec8c4SKever Yang u32 len = sizeof(struct rk_flash_info); 281f16e43f8SFrank Wang struct rk_flash_info finfo = { 282e66d4537SJon Lin .block_size = ROCKCHIP_FLASH_BLOCK_SIZE, 283f16e43f8SFrank Wang .ecc_bits = 0, 284e66d4537SJon Lin .page_size = ROCKCHIP_FLASH_PAGE_SIZE, 285f16e43f8SFrank Wang .access_time = 40, 286f16e43f8SFrank Wang .manufacturer = 0, 287f16e43f8SFrank Wang .flash_mask = 0 288f16e43f8SFrank Wang }; 289f16e43f8SFrank Wang 2900aca89f2SYifeng Zhao /* Set the raw block size for tools to creat GPT with 4K block size */ 2910aca89f2SYifeng Zhao if (desc->rawblksz == 0x1000) 2920aca89f2SYifeng Zhao finfo.manufacturer = 208; 2930aca89f2SYifeng Zhao 294e66d4537SJon Lin finfo.flash_size = (u32)desc->lba; 295e66d4537SJon Lin 296e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD && 297e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND || 298e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) { 299e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv; 300e66d4537SJon Lin 301e66d4537SJon Lin if (mtd) { 302e66d4537SJon Lin finfo.block_size = mtd->erasesize >> 9; 303e66d4537SJon Lin finfo.page_size = mtd->writesize >> 9; 30426b169f6SJon Lin #ifdef CONFIG_SUPPORT_USBPLUG 30526b169f6SJon Lin /* Using 4KB pagesize as 2KB for idblock */ 30626b169f6SJon Lin if (finfo.page_size == 8 && desc->devnum == BLK_MTD_SPI_NAND) 30726b169f6SJon Lin finfo.page_size |= (4 << 4); 30826b169f6SJon Lin #endif 309e66d4537SJon Lin } 310e66d4537SJon Lin } 311e66d4537SJon Lin 31265a0fed9SJon Lin if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) { 31365a0fed9SJon Lin /* RV1126/RK3308 mtd spinor keep the former upgrade mode */ 31465a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308) 315b8e5601dSJon Lin finfo.block_size = 0x80; /* Aligned to 64KB */ 31665a0fed9SJon Lin #else 31765a0fed9SJon Lin finfo.block_size = ROCKCHIP_FLASH_BLOCK_SIZE; 31865a0fed9SJon Lin #endif 31965a0fed9SJon Lin } 32065a0fed9SJon Lin 321e66d4537SJon Lin debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size, 322e66d4537SJon Lin finfo.page_size); 323e66d4537SJon Lin 324f16e43f8SFrank Wang if (finfo.flash_size) 325f16e43f8SFrank Wang finfo.flash_mask = 1; 326f16e43f8SFrank Wang 327f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 328f16e43f8SFrank Wang memcpy((void *)&buf[0], (void *)&finfo, len); 329f16e43f8SFrank Wang 330f16e43f8SFrank Wang /* Set data xfer size */ 331f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 332d23ec8c4SKever Yang /* legacy upgrade_tool does not set correct transfer size */ 333d23ec8c4SKever Yang common->data_size = len; 334f16e43f8SFrank Wang 335f16e43f8SFrank Wang return len; 336f16e43f8SFrank Wang } 337f16e43f8SFrank Wang 338829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common, 339829f2b85SFrank Wang struct fsg_buffhd *bh) 340829f2b85SFrank Wang { 341829f2b85SFrank Wang u8 *buf = (u8 *)bh->buf; 342829f2b85SFrank Wang u32 len = common->data_size; 343829f2b85SFrank Wang u32 chip_info[4]; 344829f2b85SFrank Wang 345829f2b85SFrank Wang memset((void *)chip_info, 0, sizeof(chip_info)); 346829f2b85SFrank Wang rockchip_rockusb_get_chip_info(chip_info); 347829f2b85SFrank Wang 348829f2b85SFrank Wang memset((void *)&buf[0], 0, len); 349829f2b85SFrank Wang memcpy((void *)&buf[0], (void *)chip_info, len); 350829f2b85SFrank Wang 351829f2b85SFrank Wang /* Set data xfer size */ 352829f2b85SFrank Wang common->residue = common->data_size_from_cmnd = len; 353829f2b85SFrank Wang 354829f2b85SFrank Wang return len; 355829f2b85SFrank Wang } 356829f2b85SFrank Wang 357f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common, 358f16e43f8SFrank Wang struct fsg_buffhd *bh) 359f16e43f8SFrank Wang { 360f16e43f8SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 361f16e43f8SFrank Wang u32 lba, amount; 362f16e43f8SFrank Wang loff_t file_offset; 363f16e43f8SFrank Wang int rc; 364f16e43f8SFrank Wang 365f16e43f8SFrank Wang lba = get_unaligned_be32(&common->cmnd[2]); 366f16e43f8SFrank Wang if (lba >= curlun->num_sectors) { 367f16e43f8SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 368f16e43f8SFrank Wang rc = -EINVAL; 369f16e43f8SFrank Wang goto out; 370f16e43f8SFrank Wang } 371f16e43f8SFrank Wang 372f16e43f8SFrank Wang file_offset = ((loff_t) lba) << 9; 373f16e43f8SFrank Wang amount = get_unaligned_be16(&common->cmnd[7]) << 9; 374f16e43f8SFrank Wang if (unlikely(amount == 0)) { 375f16e43f8SFrank Wang curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 376f16e43f8SFrank Wang rc = -EIO; 377f16e43f8SFrank Wang goto out; 378f16e43f8SFrank Wang } 379f16e43f8SFrank Wang 380f16e43f8SFrank Wang /* Perform the erase */ 381f16e43f8SFrank Wang rc = ums[common->lun].erase_sector(&ums[common->lun], 382f16e43f8SFrank Wang file_offset / SECTOR_SIZE, 383f16e43f8SFrank Wang amount / SECTOR_SIZE); 384f16e43f8SFrank Wang if (!rc) { 385f16e43f8SFrank Wang curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 386f16e43f8SFrank Wang rc = -EIO; 387f16e43f8SFrank Wang } 388f16e43f8SFrank Wang 389f16e43f8SFrank Wang out: 390f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 391f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 392f16e43f8SFrank Wang 393f16e43f8SFrank Wang return rc; 394f16e43f8SFrank Wang } 395f16e43f8SFrank Wang 396e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common, 397e66d4537SJon Lin struct fsg_buffhd *bh) 398e66d4537SJon Lin { 399e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 400e66d4537SJon Lin struct fsg_lun *curlun = &common->luns[common->lun]; 401e66d4537SJon Lin u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE; 402e66d4537SJon Lin u32 lba, amount; 403e66d4537SJon Lin loff_t file_offset; 404e66d4537SJon Lin int rc; 405e66d4537SJon Lin 406e66d4537SJon Lin lba = get_unaligned_be32(&common->cmnd[2]); 407e66d4537SJon Lin if (lba >= curlun->num_sectors) { 408e66d4537SJon Lin curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 409e66d4537SJon Lin rc = -EINVAL; 410e66d4537SJon Lin goto out; 411e66d4537SJon Lin } 412e66d4537SJon Lin 413e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD && 414e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND || 415e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) { 416e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv; 417e66d4537SJon Lin 418e66d4537SJon Lin if (mtd) 419e66d4537SJon Lin block_size = mtd->erasesize >> 9; 420e66d4537SJon Lin } 421e66d4537SJon Lin 422e66d4537SJon Lin file_offset = ((loff_t)lba) * block_size; 423e66d4537SJon Lin amount = get_unaligned_be16(&common->cmnd[7]) * block_size; 424e66d4537SJon Lin 425e66d4537SJon Lin debug("%s lba= %x, nsec= %x\n", __func__, lba, 426e66d4537SJon Lin (u32)get_unaligned_be16(&common->cmnd[7])); 427e66d4537SJon Lin 428e66d4537SJon Lin if (unlikely(amount == 0)) { 429e66d4537SJon Lin curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 430e66d4537SJon Lin rc = -EIO; 431e66d4537SJon Lin goto out; 432e66d4537SJon Lin } 433e66d4537SJon Lin 434e66d4537SJon Lin /* Perform the erase */ 435e66d4537SJon Lin rc = ums[common->lun].erase_sector(&ums[common->lun], 436e66d4537SJon Lin file_offset, 437e66d4537SJon Lin amount); 438e66d4537SJon Lin if (!rc) { 439e66d4537SJon Lin curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 440e66d4537SJon Lin rc = -EIO; 441e66d4537SJon Lin } 442e66d4537SJon Lin 443e66d4537SJon Lin out: 444e66d4537SJon Lin common->data_dir = DATA_DIR_NONE; 445e66d4537SJon Lin bh->state = BUF_STATE_EMPTY; 446e66d4537SJon Lin 447e66d4537SJon Lin return rc; 448e66d4537SJon Lin } 449e66d4537SJon Lin 4500d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 4510d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common) 4520d0c3248SFrank Wang { 4530d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 4540d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 4550d0c3248SFrank Wang struct vendor_item *vhead; 4560d0c3248SFrank Wang struct fsg_buffhd *bh; 4570d0c3248SFrank Wang void *data; 4580d0c3248SFrank Wang int rc; 4590d0c3248SFrank Wang 4600d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 4610d0c3248SFrank Wang /* _MUST_ small than 64K */ 4620d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 4630d0c3248SFrank Wang return -EINVAL; 4640d0c3248SFrank Wang } 4650d0c3248SFrank Wang 4660d0c3248SFrank Wang common->residue = common->data_size; 4670d0c3248SFrank Wang common->usb_amount_left = common->data_size; 4680d0c3248SFrank Wang 4690d0c3248SFrank Wang /* Carry out the file writes */ 4700d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 4710d0c3248SFrank Wang return -EIO; /* No data to write */ 4720d0c3248SFrank Wang 4730d0c3248SFrank Wang for (;;) { 4740d0c3248SFrank Wang if (common->usb_amount_left > 0) { 4750d0c3248SFrank Wang /* Wait for the next buffer to become available */ 4760d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 4770d0c3248SFrank Wang if (bh->state != BUF_STATE_EMPTY) 4780d0c3248SFrank Wang goto wait; 4790d0c3248SFrank Wang 4800d0c3248SFrank Wang /* Request the next buffer */ 4810d0c3248SFrank Wang common->usb_amount_left -= common->data_size; 4820d0c3248SFrank Wang bh->outreq->length = common->data_size; 4830d0c3248SFrank Wang bh->bulk_out_intended_length = common->data_size; 4840d0c3248SFrank Wang bh->outreq->short_not_ok = 1; 4850d0c3248SFrank Wang 4860d0c3248SFrank Wang START_TRANSFER_OR(common, bulk_out, bh->outreq, 4870d0c3248SFrank Wang &bh->outreq_busy, &bh->state) 4880d0c3248SFrank Wang /* 4890d0c3248SFrank Wang * Don't know what to do if 4900d0c3248SFrank Wang * common->fsg is NULL 4910d0c3248SFrank Wang */ 4920d0c3248SFrank Wang return -EIO; 4930d0c3248SFrank Wang common->next_buffhd_to_fill = bh->next; 4940d0c3248SFrank Wang } else { 4950d0c3248SFrank Wang /* Then, wait for the data to become available */ 4960d0c3248SFrank Wang bh = common->next_buffhd_to_drain; 4970d0c3248SFrank Wang if (bh->state != BUF_STATE_FULL) 4980d0c3248SFrank Wang goto wait; 4990d0c3248SFrank Wang 5000d0c3248SFrank Wang common->next_buffhd_to_drain = bh->next; 5010d0c3248SFrank Wang bh->state = BUF_STATE_EMPTY; 5020d0c3248SFrank Wang 5030d0c3248SFrank Wang /* Did something go wrong with the transfer? */ 5040d0c3248SFrank Wang if (bh->outreq->status != 0) { 5050d0c3248SFrank Wang curlun->sense_data = SS_COMMUNICATION_FAILURE; 5060d0c3248SFrank Wang curlun->info_valid = 1; 5070d0c3248SFrank Wang break; 5080d0c3248SFrank Wang } 5090d0c3248SFrank Wang 5100d0c3248SFrank Wang /* Perform the write */ 5110d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 5120d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 5130d0c3248SFrank Wang 5140d0c3248SFrank Wang if (!type) { 51570990948SYifeng Zhao #ifndef CONFIG_SUPPORT_USBPLUG 516420ee9d5SJoseph Chen if (vhead->id == HDCP_14_HDMI_ID || 51778dcc928SZhang Yubing vhead->id == HDCP_14_HDMIRX_ID || 51878dcc928SZhang Yubing vhead->id == HDCP_14_DP_ID) { 519420ee9d5SJoseph Chen rc = vendor_handle_hdcp(vhead); 520420ee9d5SJoseph Chen if (rc < 0) { 521420ee9d5SJoseph Chen curlun->sense_data = SS_WRITE_ERROR; 522420ee9d5SJoseph Chen return -EIO; 523420ee9d5SJoseph Chen } 524420ee9d5SJoseph Chen } 52570990948SYifeng Zhao #endif 526420ee9d5SJoseph Chen 5270d0c3248SFrank Wang /* Vendor storage */ 5280d0c3248SFrank Wang rc = vendor_storage_write(vhead->id, 5290d0c3248SFrank Wang (char __user *)data, 5300d0c3248SFrank Wang vhead->size); 53119652be0SFrank Wang if (rc < 0) { 53219652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 5330d0c3248SFrank Wang return -EIO; 53419652be0SFrank Wang } 5352122174dSWu Liangqing } else if (type == 1) { 5360d0c3248SFrank Wang /* RPMB */ 5376f0347c8Stony.xu rc = 5386f0347c8Stony.xu write_keybox_to_secure_storage((u8 *)data, 5396f0347c8Stony.xu vhead->size); 54019652be0SFrank Wang if (rc < 0) { 54119652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 5426f0347c8Stony.xu return -EIO; 5430d0c3248SFrank Wang } 5442122174dSWu Liangqing } else if (type == 2) { 5452122174dSWu Liangqing /* security storage */ 5462122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER 5472122174dSWu Liangqing debug("%s call rk_avb_write_perm_attr %d, %d\n", 5482122174dSWu Liangqing __func__, vhead->id, vhead->size); 5492122174dSWu Liangqing rc = rk_avb_write_perm_attr(vhead->id, 5502122174dSWu Liangqing (char __user *)data, 5512122174dSWu Liangqing vhead->size); 5522122174dSWu Liangqing if (rc < 0) { 5532122174dSWu Liangqing curlun->sense_data = SS_WRITE_ERROR; 5542122174dSWu Liangqing return -EIO; 5552122174dSWu Liangqing } 5562122174dSWu Liangqing #else 5572122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER\n"); 5582122174dSWu Liangqing #endif 559850ced9dSHisping Lin } else if (type == 3) { 560850ced9dSHisping Lin /* efuse or otp*/ 561850ced9dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT 562850ced9dSHisping Lin if (memcmp(data, "TAEK", 4) == 0) { 563850ced9dSHisping Lin if (vhead->size - 8 != 32) { 564850ced9dSHisping Lin printf("check ta encryption key size fail!\n"); 565850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 566850ced9dSHisping Lin return -EIO; 567850ced9dSHisping Lin } 568850ced9dSHisping Lin if (trusty_write_ta_encryption_key((uint32_t *)(data + 8), 8) != 0) { 569850ced9dSHisping Lin printf("trusty_write_ta_encryption_key error!"); 570850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 571850ced9dSHisping Lin return -EIO; 572850ced9dSHisping Lin } 573a43611afSHisping Lin } else if (memcmp(data, "EHUK", 4) == 0) { 574a43611afSHisping Lin if (vhead->size - 8 != 32) { 575a43611afSHisping Lin printf("check oem huk size fail!\n"); 576a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 577a43611afSHisping Lin return -EIO; 578a43611afSHisping Lin } 579a43611afSHisping Lin if (trusty_write_oem_huk((uint32_t *)(data + 8), 8) != 0) { 580a43611afSHisping Lin printf("trusty_write_oem_huk error!"); 581a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 582a43611afSHisping Lin return -EIO; 583a43611afSHisping Lin } 584005bd059SHisping Lin } else if (memcmp(data, "ENDA", 4) == 0) { 585005bd059SHisping Lin if (vhead->size - 8 != 16) { 586005bd059SHisping Lin printf("check oem encrypt data size fail!\n"); 587005bd059SHisping Lin curlun->sense_data = SS_WRITE_ERROR; 588005bd059SHisping Lin return -EIO; 589005bd059SHisping Lin } 590005bd059SHisping Lin if (trusty_write_oem_encrypt_data((uint32_t *)(data + 8), 4) != 0) { 591005bd059SHisping Lin printf("trusty_write_oem_encrypt_data error!"); 592005bd059SHisping Lin curlun->sense_data = SS_WRITE_ERROR; 593005bd059SHisping Lin return -EIO; 594005bd059SHisping Lin } 5951dd9b2ceSHisping Lin } else if (memcmp(data, "OTPK", 4) == 0) { 5961dd9b2ceSHisping Lin uint32_t key_len = vhead->size - 9; 5971dd9b2ceSHisping Lin uint8_t key_id = *((uint8_t *)data + 8); 5981dd9b2ceSHisping Lin if (key_len != 16 && key_len != 24 && key_len != 32) { 5991dd9b2ceSHisping Lin printf("check oem otp key size fail!\n"); 6001dd9b2ceSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 6011dd9b2ceSHisping Lin return -EIO; 6021dd9b2ceSHisping Lin } 6031dd9b2ceSHisping Lin if (trusty_write_oem_otp_key(key_id, (uint8_t *)(data + 9), key_len) != 0) { 6041dd9b2ceSHisping Lin printf("trusty_write_oem_huk error!"); 6051dd9b2ceSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 6061dd9b2ceSHisping Lin return -EIO; 6071dd9b2ceSHisping Lin } 608850ced9dSHisping Lin } else { 609850ced9dSHisping Lin printf("Unknown tag\n"); 610850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 611850ced9dSHisping Lin return -EIO; 612850ced9dSHisping Lin } 613850ced9dSHisping Lin #else 614850ced9dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n"); 615850ced9dSHisping Lin #endif 6162122174dSWu Liangqing } else { 6172122174dSWu Liangqing return -EINVAL; 61819652be0SFrank Wang } 6190d0c3248SFrank Wang 6200d0c3248SFrank Wang common->residue -= common->data_size; 6210d0c3248SFrank Wang 6220d0c3248SFrank Wang /* Did the host decide to stop early? */ 6230d0c3248SFrank Wang if (bh->outreq->actual != bh->outreq->length) 6240d0c3248SFrank Wang common->short_packet_received = 1; 6250d0c3248SFrank Wang break; /* Command done */ 6260d0c3248SFrank Wang } 6270d0c3248SFrank Wang wait: 6280d0c3248SFrank Wang /* Wait for something to happen */ 6290d0c3248SFrank Wang rc = sleep_thread(common); 6300d0c3248SFrank Wang if (rc) 6310d0c3248SFrank Wang return rc; 6320d0c3248SFrank Wang } 6330d0c3248SFrank Wang 6340d0c3248SFrank Wang return -EIO; /* No default reply */ 6350d0c3248SFrank Wang } 6360d0c3248SFrank Wang 6370d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common) 6380d0c3248SFrank Wang { 6390d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 6400d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 6410d0c3248SFrank Wang struct vendor_item *vhead; 6420d0c3248SFrank Wang struct fsg_buffhd *bh; 6430d0c3248SFrank Wang void *data; 6440d0c3248SFrank Wang int rc; 6450d0c3248SFrank Wang 6460d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 6470d0c3248SFrank Wang /* _MUST_ small than 64K */ 6480d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 6490d0c3248SFrank Wang return -EINVAL; 6500d0c3248SFrank Wang } 6510d0c3248SFrank Wang 6520d0c3248SFrank Wang common->residue = common->data_size; 6530d0c3248SFrank Wang common->usb_amount_left = common->data_size; 6540d0c3248SFrank Wang 6550d0c3248SFrank Wang /* Carry out the file reads */ 6560d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 6570d0c3248SFrank Wang return -EIO; /* No default reply */ 6580d0c3248SFrank Wang 6590d0c3248SFrank Wang for (;;) { 6600d0c3248SFrank Wang /* Wait for the next buffer to become available */ 6610d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 6620d0c3248SFrank Wang while (bh->state != BUF_STATE_EMPTY) { 6630d0c3248SFrank Wang rc = sleep_thread(common); 6640d0c3248SFrank Wang if (rc) 6650d0c3248SFrank Wang return rc; 6660d0c3248SFrank Wang } 6670d0c3248SFrank Wang 6680d0c3248SFrank Wang memset(bh->buf, 0, FSG_BUFLEN); 6690d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 6700d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 6710d0c3248SFrank Wang vhead->id = get_unaligned_be16(&common->cmnd[2]); 6720d0c3248SFrank Wang 6730d0c3248SFrank Wang if (!type) { 6740d0c3248SFrank Wang /* Vendor storage */ 6750d0c3248SFrank Wang rc = vendor_storage_read(vhead->id, 6760d0c3248SFrank Wang (char __user *)data, 6770d0c3248SFrank Wang common->data_size); 67819652be0SFrank Wang if (!rc) { 67919652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 6800d0c3248SFrank Wang return -EIO; 68119652be0SFrank Wang } 6820d0c3248SFrank Wang vhead->size = rc; 6832122174dSWu Liangqing } else if (type == 1) { 6840d0c3248SFrank Wang /* RPMB */ 685700a3668STony Xu rc = 686700a3668STony Xu read_raw_data_from_secure_storage((u8 *)data, 687700a3668STony Xu common->data_size); 68819652be0SFrank Wang if (!rc) { 68919652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 690700a3668STony Xu return -EIO; 69119652be0SFrank Wang } 692700a3668STony Xu vhead->size = rc; 6932122174dSWu Liangqing } else if (type == 2) { 6942122174dSWu Liangqing /* security storage */ 6952122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER 6962122174dSWu Liangqing rc = rk_avb_read_perm_attr(vhead->id, 6972122174dSWu Liangqing (char __user *)data, 6982122174dSWu Liangqing vhead->size); 6992122174dSWu Liangqing if (rc < 0) 7002122174dSWu Liangqing return -EIO; 7012122174dSWu Liangqing vhead->size = rc; 7022122174dSWu Liangqing #else 7032122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n"); 7042122174dSWu Liangqing #endif 70547c8f13dSHisping Lin } else if (type == 3) { 70647c8f13dSHisping Lin /* efuse or otp*/ 70747c8f13dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT 70847c8f13dSHisping Lin if (vhead->id == 120) { 70947c8f13dSHisping Lin u8 value; 71047c8f13dSHisping Lin char *written_str = "key is written!"; 71147c8f13dSHisping Lin char *not_written_str = "key is not written!"; 71247c8f13dSHisping Lin if (trusty_ta_encryption_key_is_written(&value) != 0) { 71347c8f13dSHisping Lin printf("trusty_ta_encryption_key_is_written error!"); 71447c8f13dSHisping Lin return -EIO; 71547c8f13dSHisping Lin } 71647c8f13dSHisping Lin if (value) { 71747c8f13dSHisping Lin memcpy(data, written_str, strlen(written_str)); 71847c8f13dSHisping Lin vhead->size = strlen(written_str); 71947c8f13dSHisping Lin } else { 72047c8f13dSHisping Lin memcpy(data, not_written_str, strlen(not_written_str)); 72147c8f13dSHisping Lin vhead->size = strlen(not_written_str); 72247c8f13dSHisping Lin } 72347c8f13dSHisping Lin } else { 72447c8f13dSHisping Lin printf("Unknown tag\n"); 72547c8f13dSHisping Lin return -EIO; 72647c8f13dSHisping Lin } 72747c8f13dSHisping Lin #else 72847c8f13dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n"); 72947c8f13dSHisping Lin #endif 7302122174dSWu Liangqing } else { 7312122174dSWu Liangqing return -EINVAL; 7320d0c3248SFrank Wang } 7330d0c3248SFrank Wang 7340d0c3248SFrank Wang common->residue -= common->data_size; 7350d0c3248SFrank Wang bh->inreq->length = common->data_size; 7360d0c3248SFrank Wang bh->state = BUF_STATE_FULL; 7370d0c3248SFrank Wang 7380d0c3248SFrank Wang break; /* No more left to read */ 7390d0c3248SFrank Wang } 7400d0c3248SFrank Wang 7410d0c3248SFrank Wang return -EIO; /* No default reply */ 7420d0c3248SFrank Wang } 7430d0c3248SFrank Wang #endif 7440d0c3248SFrank Wang 7454d2787f5SJon Lin static int rkusb_do_switch_storage(struct fsg_common *common) 7464d2787f5SJon Lin { 7474d2787f5SJon Lin enum if_type type, cur_type = ums[common->lun].block_dev.if_type; 7484d2787f5SJon Lin int devnum, cur_devnum = ums[common->lun].block_dev.devnum; 7494d2787f5SJon Lin struct blk_desc *block_dev; 7504d2787f5SJon Lin u32 media = BOOT_TYPE_UNKNOWN; 7514d2787f5SJon Lin 7524d2787f5SJon Lin media = 1 << common->cmnd[1]; 7534d2787f5SJon Lin 7544d2787f5SJon Lin switch (media) { 75522c2f449SJon Lin #ifdef CONFIG_MMC 7564d2787f5SJon Lin case BOOT_TYPE_EMMC: 7574d2787f5SJon Lin type = IF_TYPE_MMC; 7584d2787f5SJon Lin devnum = 0; 7594d2787f5SJon Lin mmc_initialize(gd->bd); 7604d2787f5SJon Lin break; 76122c2f449SJon Lin #endif 7624d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_NAND: 7634d2787f5SJon Lin type = IF_TYPE_MTD; 7644d2787f5SJon Lin devnum = 0; 7654d2787f5SJon Lin break; 7664d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_SPI_NAND: 7674d2787f5SJon Lin type = IF_TYPE_MTD; 7684d2787f5SJon Lin devnum = 1; 7694d2787f5SJon Lin break; 7704d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_SPI_NOR: 7714d2787f5SJon Lin type = IF_TYPE_MTD; 7724d2787f5SJon Lin devnum = 2; 7734d2787f5SJon Lin break; 7741b375c35SYifeng Zhao #if defined(CONFIG_SCSI) && defined(CONFIG_CMD_SCSI) && (defined(CONFIG_AHCI) || defined(CONFIG_UFS)) 7751b375c35SYifeng Zhao case BOOT_TYPE_SATA: 7761b375c35SYifeng Zhao type = IF_TYPE_SCSI; 7771b375c35SYifeng Zhao devnum = 0; 7781b375c35SYifeng Zhao break; 7791b375c35SYifeng Zhao #endif 7804d2787f5SJon Lin default: 7814d2787f5SJon Lin printf("Bootdev 0x%x is not support\n", media); 7824d2787f5SJon Lin return -ENODEV; 7834d2787f5SJon Lin } 7844d2787f5SJon Lin 7854d2787f5SJon Lin if (cur_type == type && cur_devnum == devnum) 7864d2787f5SJon Lin return 0; 7874d2787f5SJon Lin 7888c6654f1SJon Lin #if CONFIG_IS_ENABLED(SUPPORT_USBPLUG) 7898c6654f1SJon Lin block_dev = usbplug_blk_get_devnum_by_type(type, devnum); 7908c6654f1SJon Lin #else 7914d2787f5SJon Lin block_dev = blk_get_devnum_by_type(type, devnum); 7928c6654f1SJon Lin #endif 7934d2787f5SJon Lin if (!block_dev) { 7944d2787f5SJon Lin printf("Bootdev if_type=%d num=%d toggle fail\n", type, devnum); 7954d2787f5SJon Lin return -ENODEV; 7964d2787f5SJon Lin } 7974d2787f5SJon Lin 798*a1b07e70SYifeng Zhao common->luns[common->lun].num_sectors = block_dev->lba; 7994d2787f5SJon Lin ums[common->lun].num_sectors = block_dev->lba; 8004d2787f5SJon Lin ums[common->lun].block_dev = *block_dev; 8014d2787f5SJon Lin 8024d2787f5SJon Lin printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 8034d2787f5SJon Lin 0, 8044d2787f5SJon Lin ums[common->lun].block_dev.devnum, 8054d2787f5SJon Lin ums[common->lun].block_dev.hwpart, 8064d2787f5SJon Lin ums[common->lun].start_sector, 8074d2787f5SJon Lin ums[common->lun].num_sectors); 8084d2787f5SJon Lin 8094d2787f5SJon Lin return 0; 8104d2787f5SJon Lin } 8114d2787f5SJon Lin 812d4cce25eSYifeng Zhao static int rkusb_do_get_storage_info(struct fsg_common *common, 813d4cce25eSYifeng Zhao struct fsg_buffhd *bh) 814d4cce25eSYifeng Zhao { 815d4cce25eSYifeng Zhao enum if_type type = ums[common->lun].block_dev.if_type; 816d4cce25eSYifeng Zhao int devnum = ums[common->lun].block_dev.devnum; 817d4cce25eSYifeng Zhao u32 media = BOOT_TYPE_UNKNOWN; 818d4cce25eSYifeng Zhao u32 len = common->data_size; 819d4cce25eSYifeng Zhao u8 *buf = (u8 *)bh->buf; 820d4cce25eSYifeng Zhao 821d4cce25eSYifeng Zhao if (len > 4) 822d4cce25eSYifeng Zhao len = 4; 823d4cce25eSYifeng Zhao 824d4cce25eSYifeng Zhao switch (type) { 825d4cce25eSYifeng Zhao case IF_TYPE_MMC: 826d4cce25eSYifeng Zhao media = BOOT_TYPE_EMMC; 827d4cce25eSYifeng Zhao break; 828d4cce25eSYifeng Zhao 829d4cce25eSYifeng Zhao case IF_TYPE_SD: 830d4cce25eSYifeng Zhao media = BOOT_TYPE_SD0; 831d4cce25eSYifeng Zhao break; 832d4cce25eSYifeng Zhao 833d4cce25eSYifeng Zhao case IF_TYPE_MTD: 834d4cce25eSYifeng Zhao if (devnum == BLK_MTD_SPI_NAND) 835d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NAND; 836d4cce25eSYifeng Zhao else if (devnum == BLK_MTD_NAND) 837d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND; 838d4cce25eSYifeng Zhao else 839d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NOR; 840d4cce25eSYifeng Zhao break; 841d4cce25eSYifeng Zhao 842d4cce25eSYifeng Zhao case IF_TYPE_SCSI: 843d4cce25eSYifeng Zhao media = BOOT_TYPE_SATA; 844d4cce25eSYifeng Zhao break; 845d4cce25eSYifeng Zhao 846d4cce25eSYifeng Zhao case IF_TYPE_RKNAND: 847d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND; 848d4cce25eSYifeng Zhao break; 8492daa60eeSJon Lin 8502daa60eeSJon Lin case IF_TYPE_NVME: 8512daa60eeSJon Lin media = BOOT_TYPE_PCIE; 8522daa60eeSJon Lin break; 8532daa60eeSJon Lin 854d4cce25eSYifeng Zhao default: 855d4cce25eSYifeng Zhao break; 856d4cce25eSYifeng Zhao } 857d4cce25eSYifeng Zhao 858d4cce25eSYifeng Zhao memcpy((void *)&buf[0], (void *)&media, len); 859d4cce25eSYifeng Zhao common->residue = len; 860d4cce25eSYifeng Zhao common->data_size_from_cmnd = len; 861d4cce25eSYifeng Zhao 862d4cce25eSYifeng Zhao return len; 863d4cce25eSYifeng Zhao } 864d4cce25eSYifeng Zhao 865f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common, 866f16e43f8SFrank Wang struct fsg_buffhd *bh) 867f16e43f8SFrank Wang { 868f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 869f16e43f8SFrank Wang u32 len = common->data_size; 870d015bf41SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 871e66d4537SJon Lin int devnum = ums[common->lun].block_dev.devnum; 872f16e43f8SFrank Wang 873f16e43f8SFrank Wang /* 874f16e43f8SFrank Wang * bit[0]: Direct LBA, 0: Disabled; 8750d0c3248SFrank Wang * bit[1]: Vendor Storage API, 0: Disabed (default); 876d015bf41SFrank Wang * bit[2]: First 4M Access, 0: Disabled; 8770d0c3248SFrank Wang * bit[3]: Read LBA On, 0: Disabed (default); 8780d0c3248SFrank Wang * bit[4]: New Vendor Storage API, 0: Disabed; 879d4cce25eSYifeng Zhao * bit[5]: Read uart data from ram 880d4cce25eSYifeng Zhao * bit[6]: Read IDB config 881d4cce25eSYifeng Zhao * bit[7]: Read SecureMode 882d4cce25eSYifeng Zhao * bit[8]: New IDB feature 883d4cce25eSYifeng Zhao * bit[9]: Get storage media info 8848168f857SYifeng Zhao * bit[10]: LBAwrite Parity 8858168f857SYifeng Zhao * bit[11]: Read Otp Data 8868168f857SYifeng Zhao * bit[12]: usb3 download 8878168f857SYifeng Zhao * bit[13]: Write OTP proof 8888168f857SYifeng Zhao * bit[14]: Write Cipher Key 8898168f857SYifeng Zhao * bit[15:63}: Reserved. 890f16e43f8SFrank Wang */ 891f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 8922daa60eeSJon Lin if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME) 8930d0c3248SFrank Wang buf[0] = BIT(0) | BIT(2) | BIT(4); 8940d0c3248SFrank Wang else 8950d0c3248SFrank Wang buf[0] = BIT(0) | BIT(4); 896f16e43f8SFrank Wang 897e66d4537SJon Lin if (type == IF_TYPE_MTD && 898e66d4537SJon Lin (devnum == BLK_MTD_NAND || 899e66d4537SJon Lin devnum == BLK_MTD_SPI_NAND)) 900e66d4537SJon Lin buf[0] |= (1 << 6); 901e66d4537SJon Lin 90265a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308) 90365a0fed9SJon Lin if (type == IF_TYPE_MTD && devnum == BLK_MTD_SPI_NOR) 90465a0fed9SJon Lin buf[0] |= (1 << 6); 90565a0fed9SJon Lin #endif 90665a0fed9SJon Lin 9070b97a2cbSJoseph Chen #if defined(CONFIG_ROCKCHIP_NEW_IDB) 908007849d8SYifeng Zhao buf[1] = BIT(0); 909007849d8SYifeng Zhao #endif 9102c0c66c1SYifeng Zhao buf[1] |= BIT(1); /* Switch Storage */ 9112c0c66c1SYifeng Zhao buf[1] |= BIT(2); /* LBAwrite Parity */ 912d4cce25eSYifeng Zhao 91336c87911Swilliam.wu if (rkusb_usb3_capable() && !rkusb_force_usb2_enabled()) 9143c7547fcSWilliam Wu buf[1] |= BIT(4); 91536c87911Swilliam.wu else 9163c7547fcSWilliam Wu buf[1] &= ~BIT(4); 91736c87911Swilliam.wu 9188168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP 9198168f857SYifeng Zhao buf[1] |= BIT(3); /* Read Otp Data */ 9208168f857SYifeng Zhao buf[1] |= BIT(5); /* Write OTP proof */ 9218168f857SYifeng Zhao buf[1] |= BIT(6); /* Write Cipher Key */ 9228168f857SYifeng Zhao #endif 9238168f857SYifeng Zhao 924f16e43f8SFrank Wang /* Set data xfer size */ 925e66d4537SJon Lin common->residue = len; 926e66d4537SJon Lin common->data_size_from_cmnd = len; 927f16e43f8SFrank Wang 928f16e43f8SFrank Wang return len; 929f16e43f8SFrank Wang } 930f16e43f8SFrank Wang 9318168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP 9328168f857SYifeng Zhao static int rkusb_do_read_otp(struct fsg_common *common, 9338168f857SYifeng Zhao struct fsg_buffhd *bh) 9348168f857SYifeng Zhao { 9358168f857SYifeng Zhao u32 len = common->data_size; 9368168f857SYifeng Zhao u32 type = common->cmnd[1]; 9378168f857SYifeng Zhao u8 *buf = (u8 *)bh->buf; 9388168f857SYifeng Zhao struct udevice *dev; 9398168f857SYifeng Zhao 9408168f857SYifeng Zhao buf[0] = 0; 9418168f857SYifeng Zhao if (type == 0) { /* soc uuid */ 9428168f857SYifeng Zhao if (!uclass_get_device_by_driver(UCLASS_MISC, DM_GET_DRIVER(rockchip_otp), &dev)) { 9438168f857SYifeng Zhao if (!misc_read(dev, CFG_CPUID_OFFSET, (void *)&buf[1], len)) 9448168f857SYifeng Zhao buf[0] = len; 9458168f857SYifeng Zhao } 9468168f857SYifeng Zhao } 9478168f857SYifeng Zhao 9488168f857SYifeng Zhao common->residue = len; 9498168f857SYifeng Zhao common->data_size_from_cmnd = len; 9508168f857SYifeng Zhao 9518168f857SYifeng Zhao return len; 9528168f857SYifeng Zhao } 9538168f857SYifeng Zhao #endif 9548168f857SYifeng Zhao 955d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common, 956d23ec8c4SKever Yang struct fsg_buffhd *bh) 957d23ec8c4SKever Yang { 958d23ec8c4SKever Yang struct usb_request *req = bh->outreq; 959d23ec8c4SKever Yang struct fsg_bulk_cb_wrap *cbw = req->buf; 960d23ec8c4SKever Yang 961d23ec8c4SKever Yang /* FIXME cbw.DataTransferLength was not set by Upgrade Tool */ 962d23ec8c4SKever Yang common->data_size = le32_to_cpu(cbw->DataTransferLength); 963d23ec8c4SKever Yang if (common->data_size == 0) { 964d23ec8c4SKever Yang common->data_size = 965d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]) << 9; 966d23ec8c4SKever Yang printf("Trasfer Length NOT set, please use new version tool\n"); 967d23ec8c4SKever Yang debug("%s %d, cmnd1 %x\n", __func__, 968d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]), 969d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[1])); 970d23ec8c4SKever Yang } 971d23ec8c4SKever Yang if (cbw->Flags & USB_BULK_IN_FLAG) 972d23ec8c4SKever Yang common->data_dir = DATA_DIR_TO_HOST; 973d23ec8c4SKever Yang else 974d23ec8c4SKever Yang common->data_dir = DATA_DIR_FROM_HOST; 975d23ec8c4SKever Yang 976d23ec8c4SKever Yang /* Not support */ 977d23ec8c4SKever Yang common->cmnd[1] = 0; 978d23ec8c4SKever Yang } 979d23ec8c4SKever Yang 980f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common, 981f16e43f8SFrank Wang struct fsg_buffhd *bh, int *reply) 982f16e43f8SFrank Wang { 983f16e43f8SFrank Wang struct usb_request *req = bh->outreq; 984f16e43f8SFrank Wang struct fsg_bulk_cb_wrap *cbw = req->buf; 985f16e43f8SFrank Wang int rc; 986f16e43f8SFrank Wang 987f16e43f8SFrank Wang dump_cbw(cbw); 988f16e43f8SFrank Wang 989f16e43f8SFrank Wang if (rkusb_check_lun(common)) { 990f16e43f8SFrank Wang *reply = -EINVAL; 991f16e43f8SFrank Wang return RKUSB_RC_ERROR; 992f16e43f8SFrank Wang } 993f16e43f8SFrank Wang 994f16e43f8SFrank Wang switch (common->cmnd[0]) { 995f16e43f8SFrank Wang case RKUSB_TEST_UNIT_READY: 996f16e43f8SFrank Wang *reply = rkusb_do_test_unit_ready(common, bh); 997f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 998f16e43f8SFrank Wang break; 999f16e43f8SFrank Wang 1000f16e43f8SFrank Wang case RKUSB_READ_FLASH_ID: 1001f16e43f8SFrank Wang *reply = rkusb_do_read_flash_id(common, bh); 1002f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 1003f16e43f8SFrank Wang break; 1004f16e43f8SFrank Wang 1005f16e43f8SFrank Wang case RKUSB_TEST_BAD_BLOCK: 1006f16e43f8SFrank Wang *reply = rkusb_do_test_bad_block(common, bh); 1007f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 1008f16e43f8SFrank Wang break; 1009f16e43f8SFrank Wang 1010e66d4537SJon Lin case RKUSB_ERASE_10_FORCE: 1011e66d4537SJon Lin *reply = rkusb_do_erase_force(common, bh); 1012e66d4537SJon Lin rc = RKUSB_RC_FINISHED; 1013e66d4537SJon Lin break; 1014e66d4537SJon Lin 1015f16e43f8SFrank Wang case RKUSB_LBA_READ_10: 10165fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 1017f16e43f8SFrank Wang common->cmnd[0] = SC_READ_10; 1018f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 1019f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 1020f16e43f8SFrank Wang break; 1021f16e43f8SFrank Wang 1022f16e43f8SFrank Wang case RKUSB_LBA_WRITE_10: 10235fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 1024f16e43f8SFrank Wang common->cmnd[0] = SC_WRITE_10; 1025f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 1026f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 1027f16e43f8SFrank Wang break; 1028f16e43f8SFrank Wang 1029f16e43f8SFrank Wang case RKUSB_READ_FLASH_INFO: 1030f16e43f8SFrank Wang *reply = rkusb_do_read_flash_info(common, bh); 1031f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 1032f16e43f8SFrank Wang break; 1033f16e43f8SFrank Wang 1034829f2b85SFrank Wang case RKUSB_GET_CHIP_VER: 1035829f2b85SFrank Wang *reply = rkusb_do_get_chip_info(common, bh); 1036829f2b85SFrank Wang rc = RKUSB_RC_FINISHED; 1037829f2b85SFrank Wang break; 1038829f2b85SFrank Wang 1039f16e43f8SFrank Wang case RKUSB_LBA_ERASE: 1040f16e43f8SFrank Wang *reply = rkusb_do_lba_erase(common, bh); 1041f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 1042f16e43f8SFrank Wang break; 1043f16e43f8SFrank Wang 10440d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 10450d0c3248SFrank Wang case RKUSB_VS_WRITE: 10460d0c3248SFrank Wang *reply = rkusb_do_vs_write(common); 10470d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 10480d0c3248SFrank Wang break; 10490d0c3248SFrank Wang 10500d0c3248SFrank Wang case RKUSB_VS_READ: 10510d0c3248SFrank Wang *reply = rkusb_do_vs_read(common); 10520d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 10530d0c3248SFrank Wang break; 10540d0c3248SFrank Wang #endif 10554d2787f5SJon Lin case RKUSB_SWITCH_STORAGE: 10564d2787f5SJon Lin *reply = rkusb_do_switch_storage(common); 10574d2787f5SJon Lin rc = RKUSB_RC_FINISHED; 10584d2787f5SJon Lin break; 1059d4cce25eSYifeng Zhao case RKUSB_GET_STORAGE_MEDIA: 1060d4cce25eSYifeng Zhao *reply = rkusb_do_get_storage_info(common, bh); 1061d4cce25eSYifeng Zhao rc = RKUSB_RC_FINISHED; 1062d4cce25eSYifeng Zhao break; 10630d0c3248SFrank Wang 1064f16e43f8SFrank Wang case RKUSB_READ_CAPACITY: 1065f16e43f8SFrank Wang *reply = rkusb_do_read_capacity(common, bh); 1066f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 1067f16e43f8SFrank Wang break; 1068f16e43f8SFrank Wang 106936c87911Swilliam.wu case RKUSB_SWITCH_USB3: 107036c87911Swilliam.wu *reply = rkusb_do_switch_to_usb3(common, bh); 107136c87911Swilliam.wu rc = RKUSB_RC_FINISHED; 107236c87911Swilliam.wu break; 107336c87911Swilliam.wu 1074f16e43f8SFrank Wang case RKUSB_RESET: 1075f16e43f8SFrank Wang *reply = rkusb_do_reset(common, bh); 1076f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 1077f16e43f8SFrank Wang break; 1078f16e43f8SFrank Wang 10798168f857SYifeng Zhao #ifdef CONFIG_ROCKCHIP_OTP 10808168f857SYifeng Zhao case RKUSB_READ_OTP_DATA: 10818168f857SYifeng Zhao *reply = rkusb_do_read_otp(common, bh); 10828168f857SYifeng Zhao rc = RKUSB_RC_FINISHED; 10838168f857SYifeng Zhao break; 10848168f857SYifeng Zhao #endif 10858168f857SYifeng Zhao 1086f16e43f8SFrank Wang case RKUSB_READ_10: 1087f16e43f8SFrank Wang case RKUSB_WRITE_10: 1088e0023032SKever Yang printf("CMD Not support, pls use new version Tool\n"); 1089e0023032SKever Yang case RKUSB_SET_DEVICE_ID: 1090f16e43f8SFrank Wang case RKUSB_ERASE_10: 1091f16e43f8SFrank Wang case RKUSB_WRITE_SPARE: 1092f16e43f8SFrank Wang case RKUSB_READ_SPARE: 1093f16e43f8SFrank Wang case RKUSB_GET_VERSION: 1094f16e43f8SFrank Wang case RKUSB_ERASE_SYS_DISK: 1095f16e43f8SFrank Wang case RKUSB_SDRAM_READ_10: 1096f16e43f8SFrank Wang case RKUSB_SDRAM_WRITE_10: 1097f16e43f8SFrank Wang case RKUSB_SDRAM_EXECUTE: 1098f16e43f8SFrank Wang case RKUSB_LOW_FORMAT: 1099f16e43f8SFrank Wang case RKUSB_SET_RESET_FLAG: 1100f16e43f8SFrank Wang case RKUSB_SPI_READ_10: 1101f16e43f8SFrank Wang case RKUSB_SPI_WRITE_10: 1102f16e43f8SFrank Wang /* Fall through */ 1103f16e43f8SFrank Wang default: 1104f16e43f8SFrank Wang rc = RKUSB_RC_UNKNOWN_CMND; 1105f16e43f8SFrank Wang break; 1106f16e43f8SFrank Wang } 1107f16e43f8SFrank Wang 1108f16e43f8SFrank Wang return rc; 1109f16e43f8SFrank Wang } 1110f16e43f8SFrank Wang 11112c0c66c1SYifeng Zhao int rkusb_do_check_parity(struct fsg_common *common) 11122c0c66c1SYifeng Zhao { 11132c0c66c1SYifeng Zhao int ret = 0, rc; 11142c0c66c1SYifeng Zhao u32 parity, i, usb_parity, lba, len; 11152c0c66c1SYifeng Zhao static u32 usb_check_buffer[1024 * 256]; 11162c0c66c1SYifeng Zhao 11172c0c66c1SYifeng Zhao usb_parity = common->cmnd[9] | (common->cmnd[10] << 8) | 11182c0c66c1SYifeng Zhao (common->cmnd[11] << 16) | (common->cmnd[12] << 24); 11192c0c66c1SYifeng Zhao 11202c0c66c1SYifeng Zhao if (common->cmnd[0] == SC_WRITE_10 && (usb_parity)) { 11212c0c66c1SYifeng Zhao lba = get_unaligned_be32(&common->cmnd[2]); 11222c0c66c1SYifeng Zhao len = common->data_size_from_cmnd >> 9; 11232c0c66c1SYifeng Zhao rc = blk_dread(&ums[common->lun].block_dev, lba, len, usb_check_buffer); 11242c0c66c1SYifeng Zhao parity = 0x000055aa; 11252c0c66c1SYifeng Zhao for (i = 0; i < len * 128; i++) 11262c0c66c1SYifeng Zhao parity += usb_check_buffer[i]; 11272c0c66c1SYifeng Zhao if (!rc || parity != usb_parity) 11282c0c66c1SYifeng Zhao common->phase_error = 1; 11292c0c66c1SYifeng Zhao } 11302c0c66c1SYifeng Zhao 11312c0c66c1SYifeng Zhao return ret; 11322c0c66c1SYifeng Zhao } 11332c0c66c1SYifeng Zhao 1134f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add); 1135