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> 174d2787f5SJon Lin #include <mmc.h> 184d2787f5SJon Lin #include <stdlib.h> 19*8c6654f1SJon Lin #include <usbplug.h> 200d0c3248SFrank Wang 210d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 220d0c3248SFrank Wang #include <asm/arch/vendor.h> 230d0c3248SFrank Wang #endif 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 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); 95c0acb0f2SFrank Wang dev->idProduct = __constant_cpu_to_le16(0xd00d); 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 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 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 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; 1615b081643SFrank Wang 1625b081643SFrank Wang rkusb_rst_code = 0; /* restore to default */ 1635b081643SFrank Wang writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 164866d7966SJoseph Chen 165f16e43f8SFrank Wang do_reset(NULL, 0, 0, NULL); 166f16e43f8SFrank Wang } 167f16e43f8SFrank Wang 168f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common, 169f16e43f8SFrank Wang struct fsg_buffhd *bh) 170f16e43f8SFrank Wang { 171f16e43f8SFrank Wang common->data_size_from_cmnd = common->cmnd[4]; 172f16e43f8SFrank Wang common->residue = 0; 173f16e43f8SFrank Wang bh->inreq->complete = __do_reset; 174f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 175f16e43f8SFrank Wang 1765b081643SFrank Wang rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1]; 177f16e43f8SFrank Wang return 0; 178f16e43f8SFrank Wang } 179f16e43f8SFrank Wang 18036c87911Swilliam.wu __weak bool rkusb_usb3_capable(void) 18136c87911Swilliam.wu { 18236c87911Swilliam.wu return false; 18336c87911Swilliam.wu } 18436c87911Swilliam.wu 18536c87911Swilliam.wu static int rkusb_do_switch_to_usb3(struct fsg_common *common, 18636c87911Swilliam.wu struct fsg_buffhd *bh) 18736c87911Swilliam.wu { 18836c87911Swilliam.wu g_dnl_set_serialnumber((char *)&common->cmnd[1]); 18936c87911Swilliam.wu rkusb_switch_to_usb3_enable(true); 19036c87911Swilliam.wu bh->state = BUF_STATE_EMPTY; 19136c87911Swilliam.wu 19236c87911Swilliam.wu return 0; 19336c87911Swilliam.wu } 19436c87911Swilliam.wu 195f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common, 196f16e43f8SFrank Wang struct fsg_buffhd *bh) 197f16e43f8SFrank Wang { 1987eb64117SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 1997eb64117SJon Lin 2007eb64117SJon Lin if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) || 2017eb64117SJon Lin desc->if_type == IF_TYPE_SPINOR) 2027eb64117SJon Lin common->residue = 0x03 << 24; /* 128KB Max block xfer for SPI Nor */ 2037eb64117SJon Lin else 204f16e43f8SFrank Wang common->residue = 0x06 << 24; /* Max block xfer support from host */ 2057eb64117SJon Lin 206f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 207f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 208f16e43f8SFrank Wang 209f16e43f8SFrank Wang return 0; 210f16e43f8SFrank Wang } 211f16e43f8SFrank Wang 212f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common, 213f16e43f8SFrank Wang struct fsg_buffhd *bh) 214f16e43f8SFrank Wang { 215f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 216e0023032SKever Yang u32 len = 5; 217d7386f60SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 218afc6362aSJon Lin u32 devnum = ums[common->lun].block_dev.devnum; 219afc6362aSJon Lin const char *str; 220f16e43f8SFrank Wang 221afc6362aSJon Lin switch (type) { 222afc6362aSJon Lin case IF_TYPE_MMC: 223afc6362aSJon Lin str = "EMMC "; 224afc6362aSJon Lin break; 225afc6362aSJon Lin case IF_TYPE_RKNAND: 226afc6362aSJon Lin str = "NAND "; 227afc6362aSJon Lin break; 228afc6362aSJon Lin case IF_TYPE_MTD: 229afc6362aSJon Lin if (devnum == BLK_MTD_SPI_NAND) 230afc6362aSJon Lin str ="SNAND"; 231afc6362aSJon Lin else if (devnum == BLK_MTD_NAND) 232afc6362aSJon Lin str = "NAND "; 233d7386f60SFrank Wang else 234afc6362aSJon Lin str = "NOR "; 235afc6362aSJon Lin break; 236afc6362aSJon Lin default: 237afc6362aSJon Lin str = "UNKN "; /* unknown */ 238afc6362aSJon Lin break; 239afc6362aSJon Lin } 240afc6362aSJon Lin 241afc6362aSJon Lin memcpy((void *)&buf[0], str, len); 242f16e43f8SFrank Wang 243f16e43f8SFrank Wang /* Set data xfer size */ 244f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 245e0023032SKever Yang common->data_size = len; 246f16e43f8SFrank Wang 247f16e43f8SFrank Wang return len; 248f16e43f8SFrank Wang } 249f16e43f8SFrank Wang 250f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common, 251f16e43f8SFrank Wang struct fsg_buffhd *bh) 252f16e43f8SFrank Wang { 253f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 254e0023032SKever Yang u32 len = 64; 255f16e43f8SFrank Wang 256f16e43f8SFrank Wang memset((void *)&buf[0], 0, 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 265f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common, 266f16e43f8SFrank Wang struct fsg_buffhd *bh) 267f16e43f8SFrank Wang { 268e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 269f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 270d23ec8c4SKever Yang u32 len = sizeof(struct rk_flash_info); 271f16e43f8SFrank Wang struct rk_flash_info finfo = { 272e66d4537SJon Lin .block_size = ROCKCHIP_FLASH_BLOCK_SIZE, 273f16e43f8SFrank Wang .ecc_bits = 0, 274e66d4537SJon Lin .page_size = ROCKCHIP_FLASH_PAGE_SIZE, 275f16e43f8SFrank Wang .access_time = 40, 276f16e43f8SFrank Wang .manufacturer = 0, 277f16e43f8SFrank Wang .flash_mask = 0 278f16e43f8SFrank Wang }; 279f16e43f8SFrank Wang 280e66d4537SJon Lin finfo.flash_size = (u32)desc->lba; 281e66d4537SJon Lin 282e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD && 283e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND || 284e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) { 285e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv; 286e66d4537SJon Lin 287e66d4537SJon Lin if (mtd) { 288e66d4537SJon Lin finfo.block_size = mtd->erasesize >> 9; 289e66d4537SJon Lin finfo.page_size = mtd->writesize >> 9; 290e66d4537SJon Lin } 291e66d4537SJon Lin } 292e66d4537SJon Lin 29365a0fed9SJon Lin if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) { 29465a0fed9SJon Lin /* RV1126/RK3308 mtd spinor keep the former upgrade mode */ 29565a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308) 296b8e5601dSJon Lin finfo.block_size = 0x80; /* Aligned to 64KB */ 29765a0fed9SJon Lin #else 29865a0fed9SJon Lin finfo.block_size = ROCKCHIP_FLASH_BLOCK_SIZE; 29965a0fed9SJon Lin #endif 30065a0fed9SJon Lin } 30165a0fed9SJon Lin 302e66d4537SJon Lin debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size, 303e66d4537SJon Lin finfo.page_size); 304e66d4537SJon Lin 305f16e43f8SFrank Wang if (finfo.flash_size) 306f16e43f8SFrank Wang finfo.flash_mask = 1; 307f16e43f8SFrank Wang 308f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 309f16e43f8SFrank Wang memcpy((void *)&buf[0], (void *)&finfo, len); 310f16e43f8SFrank Wang 311f16e43f8SFrank Wang /* Set data xfer size */ 312f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 313d23ec8c4SKever Yang /* legacy upgrade_tool does not set correct transfer size */ 314d23ec8c4SKever Yang common->data_size = len; 315f16e43f8SFrank Wang 316f16e43f8SFrank Wang return len; 317f16e43f8SFrank Wang } 318f16e43f8SFrank Wang 319829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common, 320829f2b85SFrank Wang struct fsg_buffhd *bh) 321829f2b85SFrank Wang { 322829f2b85SFrank Wang u8 *buf = (u8 *)bh->buf; 323829f2b85SFrank Wang u32 len = common->data_size; 324829f2b85SFrank Wang u32 chip_info[4]; 325829f2b85SFrank Wang 326829f2b85SFrank Wang memset((void *)chip_info, 0, sizeof(chip_info)); 327829f2b85SFrank Wang rockchip_rockusb_get_chip_info(chip_info); 328829f2b85SFrank Wang 329829f2b85SFrank Wang memset((void *)&buf[0], 0, len); 330829f2b85SFrank Wang memcpy((void *)&buf[0], (void *)chip_info, len); 331829f2b85SFrank Wang 332829f2b85SFrank Wang /* Set data xfer size */ 333829f2b85SFrank Wang common->residue = common->data_size_from_cmnd = len; 334829f2b85SFrank Wang 335829f2b85SFrank Wang return len; 336829f2b85SFrank Wang } 337829f2b85SFrank Wang 338f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common, 339f16e43f8SFrank Wang struct fsg_buffhd *bh) 340f16e43f8SFrank Wang { 341f16e43f8SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 342f16e43f8SFrank Wang u32 lba, amount; 343f16e43f8SFrank Wang loff_t file_offset; 344f16e43f8SFrank Wang int rc; 345f16e43f8SFrank Wang 346f16e43f8SFrank Wang lba = get_unaligned_be32(&common->cmnd[2]); 347f16e43f8SFrank Wang if (lba >= curlun->num_sectors) { 348f16e43f8SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 349f16e43f8SFrank Wang rc = -EINVAL; 350f16e43f8SFrank Wang goto out; 351f16e43f8SFrank Wang } 352f16e43f8SFrank Wang 353f16e43f8SFrank Wang file_offset = ((loff_t) lba) << 9; 354f16e43f8SFrank Wang amount = get_unaligned_be16(&common->cmnd[7]) << 9; 355f16e43f8SFrank Wang if (unlikely(amount == 0)) { 356f16e43f8SFrank Wang curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 357f16e43f8SFrank Wang rc = -EIO; 358f16e43f8SFrank Wang goto out; 359f16e43f8SFrank Wang } 360f16e43f8SFrank Wang 361f16e43f8SFrank Wang /* Perform the erase */ 362f16e43f8SFrank Wang rc = ums[common->lun].erase_sector(&ums[common->lun], 363f16e43f8SFrank Wang file_offset / SECTOR_SIZE, 364f16e43f8SFrank Wang amount / SECTOR_SIZE); 365f16e43f8SFrank Wang if (!rc) { 366f16e43f8SFrank Wang curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 367f16e43f8SFrank Wang rc = -EIO; 368f16e43f8SFrank Wang } 369f16e43f8SFrank Wang 370f16e43f8SFrank Wang out: 371f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 372f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 373f16e43f8SFrank Wang 374f16e43f8SFrank Wang return rc; 375f16e43f8SFrank Wang } 376f16e43f8SFrank Wang 377e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common, 378e66d4537SJon Lin struct fsg_buffhd *bh) 379e66d4537SJon Lin { 380e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 381e66d4537SJon Lin struct fsg_lun *curlun = &common->luns[common->lun]; 382e66d4537SJon Lin u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE; 383e66d4537SJon Lin u32 lba, amount; 384e66d4537SJon Lin loff_t file_offset; 385e66d4537SJon Lin int rc; 386e66d4537SJon Lin 387e66d4537SJon Lin lba = get_unaligned_be32(&common->cmnd[2]); 388e66d4537SJon Lin if (lba >= curlun->num_sectors) { 389e66d4537SJon Lin curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 390e66d4537SJon Lin rc = -EINVAL; 391e66d4537SJon Lin goto out; 392e66d4537SJon Lin } 393e66d4537SJon Lin 394e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD && 395e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND || 396e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) { 397e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv; 398e66d4537SJon Lin 399e66d4537SJon Lin if (mtd) 400e66d4537SJon Lin block_size = mtd->erasesize >> 9; 401e66d4537SJon Lin } 402e66d4537SJon Lin 403e66d4537SJon Lin file_offset = ((loff_t)lba) * block_size; 404e66d4537SJon Lin amount = get_unaligned_be16(&common->cmnd[7]) * block_size; 405e66d4537SJon Lin 406e66d4537SJon Lin debug("%s lba= %x, nsec= %x\n", __func__, lba, 407e66d4537SJon Lin (u32)get_unaligned_be16(&common->cmnd[7])); 408e66d4537SJon Lin 409e66d4537SJon Lin if (unlikely(amount == 0)) { 410e66d4537SJon Lin curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 411e66d4537SJon Lin rc = -EIO; 412e66d4537SJon Lin goto out; 413e66d4537SJon Lin } 414e66d4537SJon Lin 415e66d4537SJon Lin /* Perform the erase */ 416e66d4537SJon Lin rc = ums[common->lun].erase_sector(&ums[common->lun], 417e66d4537SJon Lin file_offset, 418e66d4537SJon Lin amount); 419e66d4537SJon Lin if (!rc) { 420e66d4537SJon Lin curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 421e66d4537SJon Lin rc = -EIO; 422e66d4537SJon Lin } 423e66d4537SJon Lin 424e66d4537SJon Lin out: 425e66d4537SJon Lin common->data_dir = DATA_DIR_NONE; 426e66d4537SJon Lin bh->state = BUF_STATE_EMPTY; 427e66d4537SJon Lin 428e66d4537SJon Lin return rc; 429e66d4537SJon Lin } 430e66d4537SJon Lin 4310d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 4320d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common) 4330d0c3248SFrank Wang { 4340d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 4350d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 4360d0c3248SFrank Wang struct vendor_item *vhead; 4370d0c3248SFrank Wang struct fsg_buffhd *bh; 4380d0c3248SFrank Wang void *data; 4390d0c3248SFrank Wang int rc; 4400d0c3248SFrank Wang 4410d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 4420d0c3248SFrank Wang /* _MUST_ small than 64K */ 4430d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 4440d0c3248SFrank Wang return -EINVAL; 4450d0c3248SFrank Wang } 4460d0c3248SFrank Wang 4470d0c3248SFrank Wang common->residue = common->data_size; 4480d0c3248SFrank Wang common->usb_amount_left = common->data_size; 4490d0c3248SFrank Wang 4500d0c3248SFrank Wang /* Carry out the file writes */ 4510d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 4520d0c3248SFrank Wang return -EIO; /* No data to write */ 4530d0c3248SFrank Wang 4540d0c3248SFrank Wang for (;;) { 4550d0c3248SFrank Wang if (common->usb_amount_left > 0) { 4560d0c3248SFrank Wang /* Wait for the next buffer to become available */ 4570d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 4580d0c3248SFrank Wang if (bh->state != BUF_STATE_EMPTY) 4590d0c3248SFrank Wang goto wait; 4600d0c3248SFrank Wang 4610d0c3248SFrank Wang /* Request the next buffer */ 4620d0c3248SFrank Wang common->usb_amount_left -= common->data_size; 4630d0c3248SFrank Wang bh->outreq->length = common->data_size; 4640d0c3248SFrank Wang bh->bulk_out_intended_length = common->data_size; 4650d0c3248SFrank Wang bh->outreq->short_not_ok = 1; 4660d0c3248SFrank Wang 4670d0c3248SFrank Wang START_TRANSFER_OR(common, bulk_out, bh->outreq, 4680d0c3248SFrank Wang &bh->outreq_busy, &bh->state) 4690d0c3248SFrank Wang /* 4700d0c3248SFrank Wang * Don't know what to do if 4710d0c3248SFrank Wang * common->fsg is NULL 4720d0c3248SFrank Wang */ 4730d0c3248SFrank Wang return -EIO; 4740d0c3248SFrank Wang common->next_buffhd_to_fill = bh->next; 4750d0c3248SFrank Wang } else { 4760d0c3248SFrank Wang /* Then, wait for the data to become available */ 4770d0c3248SFrank Wang bh = common->next_buffhd_to_drain; 4780d0c3248SFrank Wang if (bh->state != BUF_STATE_FULL) 4790d0c3248SFrank Wang goto wait; 4800d0c3248SFrank Wang 4810d0c3248SFrank Wang common->next_buffhd_to_drain = bh->next; 4820d0c3248SFrank Wang bh->state = BUF_STATE_EMPTY; 4830d0c3248SFrank Wang 4840d0c3248SFrank Wang /* Did something go wrong with the transfer? */ 4850d0c3248SFrank Wang if (bh->outreq->status != 0) { 4860d0c3248SFrank Wang curlun->sense_data = SS_COMMUNICATION_FAILURE; 4870d0c3248SFrank Wang curlun->info_valid = 1; 4880d0c3248SFrank Wang break; 4890d0c3248SFrank Wang } 4900d0c3248SFrank Wang 4910d0c3248SFrank Wang /* Perform the write */ 4920d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 4930d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 4940d0c3248SFrank Wang 4950d0c3248SFrank Wang if (!type) { 49670990948SYifeng Zhao #ifndef CONFIG_SUPPORT_USBPLUG 497420ee9d5SJoseph Chen if (vhead->id == HDCP_14_HDMI_ID || 49878dcc928SZhang Yubing vhead->id == HDCP_14_HDMIRX_ID || 49978dcc928SZhang Yubing vhead->id == HDCP_14_DP_ID) { 500420ee9d5SJoseph Chen rc = vendor_handle_hdcp(vhead); 501420ee9d5SJoseph Chen if (rc < 0) { 502420ee9d5SJoseph Chen curlun->sense_data = SS_WRITE_ERROR; 503420ee9d5SJoseph Chen return -EIO; 504420ee9d5SJoseph Chen } 505420ee9d5SJoseph Chen } 50670990948SYifeng Zhao #endif 507420ee9d5SJoseph Chen 5080d0c3248SFrank Wang /* Vendor storage */ 5090d0c3248SFrank Wang rc = vendor_storage_write(vhead->id, 5100d0c3248SFrank Wang (char __user *)data, 5110d0c3248SFrank Wang vhead->size); 51219652be0SFrank Wang if (rc < 0) { 51319652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 5140d0c3248SFrank Wang return -EIO; 51519652be0SFrank Wang } 5162122174dSWu Liangqing } else if (type == 1) { 5170d0c3248SFrank Wang /* RPMB */ 5186f0347c8Stony.xu rc = 5196f0347c8Stony.xu write_keybox_to_secure_storage((u8 *)data, 5206f0347c8Stony.xu vhead->size); 52119652be0SFrank Wang if (rc < 0) { 52219652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 5236f0347c8Stony.xu return -EIO; 5240d0c3248SFrank Wang } 5252122174dSWu Liangqing } else if (type == 2) { 5262122174dSWu Liangqing /* security storage */ 5272122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER 5282122174dSWu Liangqing debug("%s call rk_avb_write_perm_attr %d, %d\n", 5292122174dSWu Liangqing __func__, vhead->id, vhead->size); 5302122174dSWu Liangqing rc = rk_avb_write_perm_attr(vhead->id, 5312122174dSWu Liangqing (char __user *)data, 5322122174dSWu Liangqing vhead->size); 5332122174dSWu Liangqing if (rc < 0) { 5342122174dSWu Liangqing curlun->sense_data = SS_WRITE_ERROR; 5352122174dSWu Liangqing return -EIO; 5362122174dSWu Liangqing } 5372122174dSWu Liangqing #else 5382122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER\n"); 5392122174dSWu Liangqing #endif 540850ced9dSHisping Lin } else if (type == 3) { 541850ced9dSHisping Lin /* efuse or otp*/ 542850ced9dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT 543850ced9dSHisping Lin if (memcmp(data, "TAEK", 4) == 0) { 544850ced9dSHisping Lin if (vhead->size - 8 != 32) { 545850ced9dSHisping Lin printf("check ta encryption key size fail!\n"); 546850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 547850ced9dSHisping Lin return -EIO; 548850ced9dSHisping Lin } 549850ced9dSHisping Lin if (trusty_write_ta_encryption_key((uint32_t *)(data + 8), 8) != 0) { 550850ced9dSHisping Lin printf("trusty_write_ta_encryption_key error!"); 551850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 552850ced9dSHisping Lin return -EIO; 553850ced9dSHisping Lin } 554a43611afSHisping Lin } else if (memcmp(data, "EHUK", 4) == 0) { 555a43611afSHisping Lin if (vhead->size - 8 != 32) { 556a43611afSHisping Lin printf("check oem huk size fail!\n"); 557a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 558a43611afSHisping Lin return -EIO; 559a43611afSHisping Lin } 560a43611afSHisping Lin if (trusty_write_oem_huk((uint32_t *)(data + 8), 8) != 0) { 561a43611afSHisping Lin printf("trusty_write_oem_huk error!"); 562a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 563a43611afSHisping Lin return -EIO; 564a43611afSHisping Lin } 565850ced9dSHisping Lin } else { 566850ced9dSHisping Lin printf("Unknown tag\n"); 567850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 568850ced9dSHisping Lin return -EIO; 569850ced9dSHisping Lin } 570850ced9dSHisping Lin #else 571850ced9dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n"); 572850ced9dSHisping Lin #endif 5732122174dSWu Liangqing } else { 5742122174dSWu Liangqing return -EINVAL; 57519652be0SFrank Wang } 5760d0c3248SFrank Wang 5770d0c3248SFrank Wang common->residue -= common->data_size; 5780d0c3248SFrank Wang 5790d0c3248SFrank Wang /* Did the host decide to stop early? */ 5800d0c3248SFrank Wang if (bh->outreq->actual != bh->outreq->length) 5810d0c3248SFrank Wang common->short_packet_received = 1; 5820d0c3248SFrank Wang break; /* Command done */ 5830d0c3248SFrank Wang } 5840d0c3248SFrank Wang wait: 5850d0c3248SFrank Wang /* Wait for something to happen */ 5860d0c3248SFrank Wang rc = sleep_thread(common); 5870d0c3248SFrank Wang if (rc) 5880d0c3248SFrank Wang return rc; 5890d0c3248SFrank Wang } 5900d0c3248SFrank Wang 5910d0c3248SFrank Wang return -EIO; /* No default reply */ 5920d0c3248SFrank Wang } 5930d0c3248SFrank Wang 5940d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common) 5950d0c3248SFrank Wang { 5960d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 5970d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 5980d0c3248SFrank Wang struct vendor_item *vhead; 5990d0c3248SFrank Wang struct fsg_buffhd *bh; 6000d0c3248SFrank Wang void *data; 6010d0c3248SFrank Wang int rc; 6020d0c3248SFrank Wang 6030d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 6040d0c3248SFrank Wang /* _MUST_ small than 64K */ 6050d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 6060d0c3248SFrank Wang return -EINVAL; 6070d0c3248SFrank Wang } 6080d0c3248SFrank Wang 6090d0c3248SFrank Wang common->residue = common->data_size; 6100d0c3248SFrank Wang common->usb_amount_left = common->data_size; 6110d0c3248SFrank Wang 6120d0c3248SFrank Wang /* Carry out the file reads */ 6130d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 6140d0c3248SFrank Wang return -EIO; /* No default reply */ 6150d0c3248SFrank Wang 6160d0c3248SFrank Wang for (;;) { 6170d0c3248SFrank Wang /* Wait for the next buffer to become available */ 6180d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 6190d0c3248SFrank Wang while (bh->state != BUF_STATE_EMPTY) { 6200d0c3248SFrank Wang rc = sleep_thread(common); 6210d0c3248SFrank Wang if (rc) 6220d0c3248SFrank Wang return rc; 6230d0c3248SFrank Wang } 6240d0c3248SFrank Wang 6250d0c3248SFrank Wang memset(bh->buf, 0, FSG_BUFLEN); 6260d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 6270d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 6280d0c3248SFrank Wang vhead->id = get_unaligned_be16(&common->cmnd[2]); 6290d0c3248SFrank Wang 6300d0c3248SFrank Wang if (!type) { 6310d0c3248SFrank Wang /* Vendor storage */ 6320d0c3248SFrank Wang rc = vendor_storage_read(vhead->id, 6330d0c3248SFrank Wang (char __user *)data, 6340d0c3248SFrank Wang common->data_size); 63519652be0SFrank Wang if (!rc) { 63619652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 6370d0c3248SFrank Wang return -EIO; 63819652be0SFrank Wang } 6390d0c3248SFrank Wang vhead->size = rc; 6402122174dSWu Liangqing } else if (type == 1) { 6410d0c3248SFrank Wang /* RPMB */ 642700a3668STony Xu rc = 643700a3668STony Xu read_raw_data_from_secure_storage((u8 *)data, 644700a3668STony Xu common->data_size); 64519652be0SFrank Wang if (!rc) { 64619652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 647700a3668STony Xu return -EIO; 64819652be0SFrank Wang } 649700a3668STony Xu vhead->size = rc; 6502122174dSWu Liangqing } else if (type == 2) { 6512122174dSWu Liangqing /* security storage */ 6522122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER 6532122174dSWu Liangqing rc = rk_avb_read_perm_attr(vhead->id, 6542122174dSWu Liangqing (char __user *)data, 6552122174dSWu Liangqing vhead->size); 6562122174dSWu Liangqing if (rc < 0) 6572122174dSWu Liangqing return -EIO; 6582122174dSWu Liangqing vhead->size = rc; 6592122174dSWu Liangqing #else 6602122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n"); 6612122174dSWu Liangqing #endif 66247c8f13dSHisping Lin } else if (type == 3) { 66347c8f13dSHisping Lin /* efuse or otp*/ 66447c8f13dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT 66547c8f13dSHisping Lin if (vhead->id == 120) { 66647c8f13dSHisping Lin u8 value; 66747c8f13dSHisping Lin char *written_str = "key is written!"; 66847c8f13dSHisping Lin char *not_written_str = "key is not written!"; 66947c8f13dSHisping Lin if (trusty_ta_encryption_key_is_written(&value) != 0) { 67047c8f13dSHisping Lin printf("trusty_ta_encryption_key_is_written error!"); 67147c8f13dSHisping Lin return -EIO; 67247c8f13dSHisping Lin } 67347c8f13dSHisping Lin if (value) { 67447c8f13dSHisping Lin memcpy(data, written_str, strlen(written_str)); 67547c8f13dSHisping Lin vhead->size = strlen(written_str); 67647c8f13dSHisping Lin } else { 67747c8f13dSHisping Lin memcpy(data, not_written_str, strlen(not_written_str)); 67847c8f13dSHisping Lin vhead->size = strlen(not_written_str); 67947c8f13dSHisping Lin } 68047c8f13dSHisping Lin } else { 68147c8f13dSHisping Lin printf("Unknown tag\n"); 68247c8f13dSHisping Lin return -EIO; 68347c8f13dSHisping Lin } 68447c8f13dSHisping Lin #else 68547c8f13dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n"); 68647c8f13dSHisping Lin #endif 6872122174dSWu Liangqing } else { 6882122174dSWu Liangqing return -EINVAL; 6890d0c3248SFrank Wang } 6900d0c3248SFrank Wang 6910d0c3248SFrank Wang common->residue -= common->data_size; 6920d0c3248SFrank Wang bh->inreq->length = common->data_size; 6930d0c3248SFrank Wang bh->state = BUF_STATE_FULL; 6940d0c3248SFrank Wang 6950d0c3248SFrank Wang break; /* No more left to read */ 6960d0c3248SFrank Wang } 6970d0c3248SFrank Wang 6980d0c3248SFrank Wang return -EIO; /* No default reply */ 6990d0c3248SFrank Wang } 7000d0c3248SFrank Wang #endif 7010d0c3248SFrank Wang 7024d2787f5SJon Lin static int rkusb_do_switch_storage(struct fsg_common *common) 7034d2787f5SJon Lin { 7044d2787f5SJon Lin enum if_type type, cur_type = ums[common->lun].block_dev.if_type; 7054d2787f5SJon Lin int devnum, cur_devnum = ums[common->lun].block_dev.devnum; 7064d2787f5SJon Lin struct blk_desc *block_dev; 7074d2787f5SJon Lin u32 media = BOOT_TYPE_UNKNOWN; 7084d2787f5SJon Lin 7094d2787f5SJon Lin media = 1 << common->cmnd[1]; 7104d2787f5SJon Lin 7114d2787f5SJon Lin switch (media) { 71222c2f449SJon Lin #ifdef CONFIG_MMC 7134d2787f5SJon Lin case BOOT_TYPE_EMMC: 7144d2787f5SJon Lin type = IF_TYPE_MMC; 7154d2787f5SJon Lin devnum = 0; 7164d2787f5SJon Lin mmc_initialize(gd->bd); 7174d2787f5SJon Lin break; 71822c2f449SJon Lin #endif 7194d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_NAND: 7204d2787f5SJon Lin type = IF_TYPE_MTD; 7214d2787f5SJon Lin devnum = 0; 7224d2787f5SJon Lin break; 7234d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_SPI_NAND: 7244d2787f5SJon Lin type = IF_TYPE_MTD; 7254d2787f5SJon Lin devnum = 1; 7264d2787f5SJon Lin break; 7274d2787f5SJon Lin case BOOT_TYPE_MTD_BLK_SPI_NOR: 7284d2787f5SJon Lin type = IF_TYPE_MTD; 7294d2787f5SJon Lin devnum = 2; 7304d2787f5SJon Lin break; 7314d2787f5SJon Lin default: 7324d2787f5SJon Lin printf("Bootdev 0x%x is not support\n", media); 7334d2787f5SJon Lin return -ENODEV; 7344d2787f5SJon Lin } 7354d2787f5SJon Lin 7364d2787f5SJon Lin if (cur_type == type && cur_devnum == devnum) 7374d2787f5SJon Lin return 0; 7384d2787f5SJon Lin 739*8c6654f1SJon Lin #if CONFIG_IS_ENABLED(SUPPORT_USBPLUG) 740*8c6654f1SJon Lin block_dev = usbplug_blk_get_devnum_by_type(type, devnum); 741*8c6654f1SJon Lin #else 7424d2787f5SJon Lin block_dev = blk_get_devnum_by_type(type, devnum); 743*8c6654f1SJon Lin #endif 7444d2787f5SJon Lin if (!block_dev) { 7454d2787f5SJon Lin printf("Bootdev if_type=%d num=%d toggle fail\n", type, devnum); 7464d2787f5SJon Lin return -ENODEV; 7474d2787f5SJon Lin } 7484d2787f5SJon Lin 7494d2787f5SJon Lin ums[common->lun].num_sectors = block_dev->lba; 7504d2787f5SJon Lin ums[common->lun].block_dev = *block_dev; 7514d2787f5SJon Lin 7524d2787f5SJon Lin printf("RKUSB: LUN %d, dev %d, hwpart %d, sector %#x, count %#x\n", 7534d2787f5SJon Lin 0, 7544d2787f5SJon Lin ums[common->lun].block_dev.devnum, 7554d2787f5SJon Lin ums[common->lun].block_dev.hwpart, 7564d2787f5SJon Lin ums[common->lun].start_sector, 7574d2787f5SJon Lin ums[common->lun].num_sectors); 7584d2787f5SJon Lin 7594d2787f5SJon Lin return 0; 7604d2787f5SJon Lin } 7614d2787f5SJon Lin 762d4cce25eSYifeng Zhao static int rkusb_do_get_storage_info(struct fsg_common *common, 763d4cce25eSYifeng Zhao struct fsg_buffhd *bh) 764d4cce25eSYifeng Zhao { 765d4cce25eSYifeng Zhao enum if_type type = ums[common->lun].block_dev.if_type; 766d4cce25eSYifeng Zhao int devnum = ums[common->lun].block_dev.devnum; 767d4cce25eSYifeng Zhao u32 media = BOOT_TYPE_UNKNOWN; 768d4cce25eSYifeng Zhao u32 len = common->data_size; 769d4cce25eSYifeng Zhao u8 *buf = (u8 *)bh->buf; 770d4cce25eSYifeng Zhao 771d4cce25eSYifeng Zhao if (len > 4) 772d4cce25eSYifeng Zhao len = 4; 773d4cce25eSYifeng Zhao 774d4cce25eSYifeng Zhao switch (type) { 775d4cce25eSYifeng Zhao case IF_TYPE_MMC: 776d4cce25eSYifeng Zhao media = BOOT_TYPE_EMMC; 777d4cce25eSYifeng Zhao break; 778d4cce25eSYifeng Zhao 779d4cce25eSYifeng Zhao case IF_TYPE_SD: 780d4cce25eSYifeng Zhao media = BOOT_TYPE_SD0; 781d4cce25eSYifeng Zhao break; 782d4cce25eSYifeng Zhao 783d4cce25eSYifeng Zhao case IF_TYPE_MTD: 784d4cce25eSYifeng Zhao if (devnum == BLK_MTD_SPI_NAND) 785d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NAND; 786d4cce25eSYifeng Zhao else if (devnum == BLK_MTD_NAND) 787d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND; 788d4cce25eSYifeng Zhao else 789d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NOR; 790d4cce25eSYifeng Zhao break; 791d4cce25eSYifeng Zhao 792d4cce25eSYifeng Zhao case IF_TYPE_SCSI: 793d4cce25eSYifeng Zhao media = BOOT_TYPE_SATA; 794d4cce25eSYifeng Zhao break; 795d4cce25eSYifeng Zhao 796d4cce25eSYifeng Zhao case IF_TYPE_RKNAND: 797d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND; 798d4cce25eSYifeng Zhao break; 7992daa60eeSJon Lin 8002daa60eeSJon Lin case IF_TYPE_NVME: 8012daa60eeSJon Lin media = BOOT_TYPE_PCIE; 8022daa60eeSJon Lin break; 8032daa60eeSJon Lin 804d4cce25eSYifeng Zhao default: 805d4cce25eSYifeng Zhao break; 806d4cce25eSYifeng Zhao } 807d4cce25eSYifeng Zhao 808d4cce25eSYifeng Zhao memcpy((void *)&buf[0], (void *)&media, len); 809d4cce25eSYifeng Zhao common->residue = len; 810d4cce25eSYifeng Zhao common->data_size_from_cmnd = len; 811d4cce25eSYifeng Zhao 812d4cce25eSYifeng Zhao return len; 813d4cce25eSYifeng Zhao } 814d4cce25eSYifeng Zhao 815f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common, 816f16e43f8SFrank Wang struct fsg_buffhd *bh) 817f16e43f8SFrank Wang { 818f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 819f16e43f8SFrank Wang u32 len = common->data_size; 820d015bf41SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 821e66d4537SJon Lin int devnum = ums[common->lun].block_dev.devnum; 822f16e43f8SFrank Wang 823f16e43f8SFrank Wang /* 824f16e43f8SFrank Wang * bit[0]: Direct LBA, 0: Disabled; 8250d0c3248SFrank Wang * bit[1]: Vendor Storage API, 0: Disabed (default); 826d015bf41SFrank Wang * bit[2]: First 4M Access, 0: Disabled; 8270d0c3248SFrank Wang * bit[3]: Read LBA On, 0: Disabed (default); 8280d0c3248SFrank Wang * bit[4]: New Vendor Storage API, 0: Disabed; 829d4cce25eSYifeng Zhao * bit[5]: Read uart data from ram 830d4cce25eSYifeng Zhao * bit[6]: Read IDB config 831d4cce25eSYifeng Zhao * bit[7]: Read SecureMode 832d4cce25eSYifeng Zhao * bit[8]: New IDB feature 833d4cce25eSYifeng Zhao * bit[9]: Get storage media info 834d4cce25eSYifeng Zhao * bit[10:63}: Reserved. 835f16e43f8SFrank Wang */ 836f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 8372daa60eeSJon Lin if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME) 8380d0c3248SFrank Wang buf[0] = BIT(0) | BIT(2) | BIT(4); 8390d0c3248SFrank Wang else 8400d0c3248SFrank Wang buf[0] = BIT(0) | BIT(4); 841f16e43f8SFrank Wang 842e66d4537SJon Lin if (type == IF_TYPE_MTD && 843e66d4537SJon Lin (devnum == BLK_MTD_NAND || 844e66d4537SJon Lin devnum == BLK_MTD_SPI_NAND)) 845e66d4537SJon Lin buf[0] |= (1 << 6); 846e66d4537SJon Lin 84765a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308) 84865a0fed9SJon Lin if (type == IF_TYPE_MTD && devnum == BLK_MTD_SPI_NOR) 84965a0fed9SJon Lin buf[0] |= (1 << 6); 85065a0fed9SJon Lin #endif 85165a0fed9SJon Lin 8520b97a2cbSJoseph Chen #if defined(CONFIG_ROCKCHIP_NEW_IDB) 853007849d8SYifeng Zhao buf[1] = BIT(0); 854007849d8SYifeng Zhao #endif 8552c0c66c1SYifeng Zhao buf[1] |= BIT(1); /* Switch Storage */ 8562c0c66c1SYifeng Zhao buf[1] |= BIT(2); /* LBAwrite Parity */ 857d4cce25eSYifeng Zhao 85836c87911Swilliam.wu if (rkusb_usb3_capable() && !rkusb_force_usb2_enabled()) 8593c7547fcSWilliam Wu buf[1] |= BIT(4); 86036c87911Swilliam.wu else 8613c7547fcSWilliam Wu buf[1] &= ~BIT(4); 86236c87911Swilliam.wu 863f16e43f8SFrank Wang /* Set data xfer size */ 864e66d4537SJon Lin common->residue = len; 865e66d4537SJon Lin common->data_size_from_cmnd = len; 866f16e43f8SFrank Wang 867f16e43f8SFrank Wang return len; 868f16e43f8SFrank Wang } 869f16e43f8SFrank Wang 870d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common, 871d23ec8c4SKever Yang struct fsg_buffhd *bh) 872d23ec8c4SKever Yang { 873d23ec8c4SKever Yang struct usb_request *req = bh->outreq; 874d23ec8c4SKever Yang struct fsg_bulk_cb_wrap *cbw = req->buf; 875d23ec8c4SKever Yang 876d23ec8c4SKever Yang /* FIXME cbw.DataTransferLength was not set by Upgrade Tool */ 877d23ec8c4SKever Yang common->data_size = le32_to_cpu(cbw->DataTransferLength); 878d23ec8c4SKever Yang if (common->data_size == 0) { 879d23ec8c4SKever Yang common->data_size = 880d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]) << 9; 881d23ec8c4SKever Yang printf("Trasfer Length NOT set, please use new version tool\n"); 882d23ec8c4SKever Yang debug("%s %d, cmnd1 %x\n", __func__, 883d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]), 884d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[1])); 885d23ec8c4SKever Yang } 886d23ec8c4SKever Yang if (cbw->Flags & USB_BULK_IN_FLAG) 887d23ec8c4SKever Yang common->data_dir = DATA_DIR_TO_HOST; 888d23ec8c4SKever Yang else 889d23ec8c4SKever Yang common->data_dir = DATA_DIR_FROM_HOST; 890d23ec8c4SKever Yang 891d23ec8c4SKever Yang /* Not support */ 892d23ec8c4SKever Yang common->cmnd[1] = 0; 893d23ec8c4SKever Yang } 894d23ec8c4SKever Yang 895f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common, 896f16e43f8SFrank Wang struct fsg_buffhd *bh, int *reply) 897f16e43f8SFrank Wang { 898f16e43f8SFrank Wang struct usb_request *req = bh->outreq; 899f16e43f8SFrank Wang struct fsg_bulk_cb_wrap *cbw = req->buf; 900f16e43f8SFrank Wang int rc; 901f16e43f8SFrank Wang 902f16e43f8SFrank Wang dump_cbw(cbw); 903f16e43f8SFrank Wang 904f16e43f8SFrank Wang if (rkusb_check_lun(common)) { 905f16e43f8SFrank Wang *reply = -EINVAL; 906f16e43f8SFrank Wang return RKUSB_RC_ERROR; 907f16e43f8SFrank Wang } 908f16e43f8SFrank Wang 909f16e43f8SFrank Wang switch (common->cmnd[0]) { 910f16e43f8SFrank Wang case RKUSB_TEST_UNIT_READY: 911f16e43f8SFrank Wang *reply = rkusb_do_test_unit_ready(common, bh); 912f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 913f16e43f8SFrank Wang break; 914f16e43f8SFrank Wang 915f16e43f8SFrank Wang case RKUSB_READ_FLASH_ID: 916f16e43f8SFrank Wang *reply = rkusb_do_read_flash_id(common, bh); 917f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 918f16e43f8SFrank Wang break; 919f16e43f8SFrank Wang 920f16e43f8SFrank Wang case RKUSB_TEST_BAD_BLOCK: 921f16e43f8SFrank Wang *reply = rkusb_do_test_bad_block(common, bh); 922f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 923f16e43f8SFrank Wang break; 924f16e43f8SFrank Wang 925e66d4537SJon Lin case RKUSB_ERASE_10_FORCE: 926e66d4537SJon Lin *reply = rkusb_do_erase_force(common, bh); 927e66d4537SJon Lin rc = RKUSB_RC_FINISHED; 928e66d4537SJon Lin break; 929e66d4537SJon Lin 930f16e43f8SFrank Wang case RKUSB_LBA_READ_10: 9315fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 932f16e43f8SFrank Wang common->cmnd[0] = SC_READ_10; 933f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 934f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 935f16e43f8SFrank Wang break; 936f16e43f8SFrank Wang 937f16e43f8SFrank Wang case RKUSB_LBA_WRITE_10: 9385fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 939f16e43f8SFrank Wang common->cmnd[0] = SC_WRITE_10; 940f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 941f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 942f16e43f8SFrank Wang break; 943f16e43f8SFrank Wang 944f16e43f8SFrank Wang case RKUSB_READ_FLASH_INFO: 945f16e43f8SFrank Wang *reply = rkusb_do_read_flash_info(common, bh); 946f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 947f16e43f8SFrank Wang break; 948f16e43f8SFrank Wang 949829f2b85SFrank Wang case RKUSB_GET_CHIP_VER: 950829f2b85SFrank Wang *reply = rkusb_do_get_chip_info(common, bh); 951829f2b85SFrank Wang rc = RKUSB_RC_FINISHED; 952829f2b85SFrank Wang break; 953829f2b85SFrank Wang 954f16e43f8SFrank Wang case RKUSB_LBA_ERASE: 955f16e43f8SFrank Wang *reply = rkusb_do_lba_erase(common, bh); 956f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 957f16e43f8SFrank Wang break; 958f16e43f8SFrank Wang 9590d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 9600d0c3248SFrank Wang case RKUSB_VS_WRITE: 9610d0c3248SFrank Wang *reply = rkusb_do_vs_write(common); 9620d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 9630d0c3248SFrank Wang break; 9640d0c3248SFrank Wang 9650d0c3248SFrank Wang case RKUSB_VS_READ: 9660d0c3248SFrank Wang *reply = rkusb_do_vs_read(common); 9670d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 9680d0c3248SFrank Wang break; 9690d0c3248SFrank Wang #endif 9704d2787f5SJon Lin case RKUSB_SWITCH_STORAGE: 9714d2787f5SJon Lin *reply = rkusb_do_switch_storage(common); 9724d2787f5SJon Lin rc = RKUSB_RC_FINISHED; 9734d2787f5SJon Lin break; 974d4cce25eSYifeng Zhao case RKUSB_GET_STORAGE_MEDIA: 975d4cce25eSYifeng Zhao *reply = rkusb_do_get_storage_info(common, bh); 976d4cce25eSYifeng Zhao rc = RKUSB_RC_FINISHED; 977d4cce25eSYifeng Zhao break; 9780d0c3248SFrank Wang 979f16e43f8SFrank Wang case RKUSB_READ_CAPACITY: 980f16e43f8SFrank Wang *reply = rkusb_do_read_capacity(common, bh); 981f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 982f16e43f8SFrank Wang break; 983f16e43f8SFrank Wang 98436c87911Swilliam.wu case RKUSB_SWITCH_USB3: 98536c87911Swilliam.wu *reply = rkusb_do_switch_to_usb3(common, bh); 98636c87911Swilliam.wu rc = RKUSB_RC_FINISHED; 98736c87911Swilliam.wu break; 98836c87911Swilliam.wu 989f16e43f8SFrank Wang case RKUSB_RESET: 990f16e43f8SFrank Wang *reply = rkusb_do_reset(common, bh); 991f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 992f16e43f8SFrank Wang break; 993f16e43f8SFrank Wang 994f16e43f8SFrank Wang case RKUSB_READ_10: 995f16e43f8SFrank Wang case RKUSB_WRITE_10: 996e0023032SKever Yang printf("CMD Not support, pls use new version Tool\n"); 997e0023032SKever Yang case RKUSB_SET_DEVICE_ID: 998f16e43f8SFrank Wang case RKUSB_ERASE_10: 999f16e43f8SFrank Wang case RKUSB_WRITE_SPARE: 1000f16e43f8SFrank Wang case RKUSB_READ_SPARE: 1001f16e43f8SFrank Wang case RKUSB_GET_VERSION: 1002f16e43f8SFrank Wang case RKUSB_ERASE_SYS_DISK: 1003f16e43f8SFrank Wang case RKUSB_SDRAM_READ_10: 1004f16e43f8SFrank Wang case RKUSB_SDRAM_WRITE_10: 1005f16e43f8SFrank Wang case RKUSB_SDRAM_EXECUTE: 1006f16e43f8SFrank Wang case RKUSB_LOW_FORMAT: 1007f16e43f8SFrank Wang case RKUSB_SET_RESET_FLAG: 1008f16e43f8SFrank Wang case RKUSB_SPI_READ_10: 1009f16e43f8SFrank Wang case RKUSB_SPI_WRITE_10: 1010f16e43f8SFrank Wang case RKUSB_SESSION: 1011f16e43f8SFrank Wang /* Fall through */ 1012f16e43f8SFrank Wang default: 1013f16e43f8SFrank Wang rc = RKUSB_RC_UNKNOWN_CMND; 1014f16e43f8SFrank Wang break; 1015f16e43f8SFrank Wang } 1016f16e43f8SFrank Wang 1017f16e43f8SFrank Wang return rc; 1018f16e43f8SFrank Wang } 1019f16e43f8SFrank Wang 10202c0c66c1SYifeng Zhao int rkusb_do_check_parity(struct fsg_common *common) 10212c0c66c1SYifeng Zhao { 10222c0c66c1SYifeng Zhao int ret = 0, rc; 10232c0c66c1SYifeng Zhao u32 parity, i, usb_parity, lba, len; 10242c0c66c1SYifeng Zhao static u32 usb_check_buffer[1024 * 256]; 10252c0c66c1SYifeng Zhao 10262c0c66c1SYifeng Zhao usb_parity = common->cmnd[9] | (common->cmnd[10] << 8) | 10272c0c66c1SYifeng Zhao (common->cmnd[11] << 16) | (common->cmnd[12] << 24); 10282c0c66c1SYifeng Zhao 10292c0c66c1SYifeng Zhao if (common->cmnd[0] == SC_WRITE_10 && (usb_parity)) { 10302c0c66c1SYifeng Zhao lba = get_unaligned_be32(&common->cmnd[2]); 10312c0c66c1SYifeng Zhao len = common->data_size_from_cmnd >> 9; 10322c0c66c1SYifeng Zhao rc = blk_dread(&ums[common->lun].block_dev, lba, len, usb_check_buffer); 10332c0c66c1SYifeng Zhao parity = 0x000055aa; 10342c0c66c1SYifeng Zhao for (i = 0; i < len * 128; i++) 10352c0c66c1SYifeng Zhao parity += usb_check_buffer[i]; 10362c0c66c1SYifeng Zhao if (!rc || parity != usb_parity) 10372c0c66c1SYifeng Zhao common->phase_error = 1; 10382c0c66c1SYifeng Zhao } 10392c0c66c1SYifeng Zhao 10402c0c66c1SYifeng Zhao return ret; 10412c0c66c1SYifeng Zhao } 10422c0c66c1SYifeng Zhao 1043f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add); 1044