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> 170d0c3248SFrank Wang 180d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 190d0c3248SFrank Wang #include <asm/arch/vendor.h> 200d0c3248SFrank Wang #endif 21f16e43f8SFrank Wang #include <rockusb.h> 22f16e43f8SFrank Wang 23f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS 0xff 24f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS 0x06 25f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL 0x05 26f16e43f8SFrank Wang 27e66d4537SJon Lin #define ROCKCHIP_FLASH_BLOCK_SIZE 1024 28e66d4537SJon Lin #define ROCKCHIP_FLASH_PAGE_SIZE 4 29e66d4537SJon Lin 30f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = { 31f16e43f8SFrank Wang .bLength = USB_DT_INTERFACE_SIZE, 32f16e43f8SFrank Wang .bDescriptorType = USB_DT_INTERFACE, 33f16e43f8SFrank Wang .bInterfaceNumber = 0x00, 34f16e43f8SFrank Wang .bAlternateSetting = 0x00, 35f16e43f8SFrank Wang .bNumEndpoints = 0x02, 36f16e43f8SFrank Wang .bInterfaceClass = ROCKUSB_INTERFACE_CLASS, 37f16e43f8SFrank Wang .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS, 38f16e43f8SFrank Wang .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL, 39f16e43f8SFrank Wang }; 40f16e43f8SFrank Wang 41f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = { 42f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc, 43f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_in_desc, 44f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_out_desc, 45f16e43f8SFrank Wang NULL, 46f16e43f8SFrank Wang }; 47f16e43f8SFrank Wang 48f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = { 49f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc, 50f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_in_desc, 51f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_out_desc, 52f16e43f8SFrank Wang NULL, 53f16e43f8SFrank Wang }; 54f16e43f8SFrank Wang 5526dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = { 5626dd3474SWilliam Wu (struct usb_descriptor_header *)&rkusb_intf_desc, 5726dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_desc, 5826dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc, 5926dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_desc, 6026dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc, 6126dd3474SWilliam Wu NULL, 6226dd3474SWilliam Wu }; 6326dd3474SWilliam Wu 64f16e43f8SFrank Wang struct rk_flash_info { 65f16e43f8SFrank Wang u32 flash_size; 66f16e43f8SFrank Wang u16 block_size; 67f16e43f8SFrank Wang u8 page_size; 68f16e43f8SFrank Wang u8 ecc_bits; 69f16e43f8SFrank Wang u8 access_time; 70f16e43f8SFrank Wang u8 manufacturer; 71f16e43f8SFrank Wang u8 flash_mask; 72f16e43f8SFrank Wang } __packed; 73f16e43f8SFrank Wang 745b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */ 755b081643SFrank Wang 76f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) 77f16e43f8SFrank Wang { 78ba437c8cSFrank Wang if (IS_RKUSB_UMS_DNL(name)) { 79c0acb0f2SFrank Wang /* Fix to Rockchip's VID and PID */ 80ba437c8cSFrank Wang dev->idVendor = __constant_cpu_to_le16(0x2207); 81ba437c8cSFrank Wang dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID); 82ba437c8cSFrank Wang 83f16e43f8SFrank Wang /* Enumerate as a loader device */ 8495424692SJoseph Chen #if defined(CONFIG_SUPPORT_USBPLUG) 8595424692SJoseph Chen dev->bcdUSB = cpu_to_le16(0x0200); 8695424692SJoseph Chen #else 87f16e43f8SFrank Wang dev->bcdUSB = cpu_to_le16(0x0201); 8895424692SJoseph Chen #endif 89c0acb0f2SFrank Wang } else if (!strncmp(name, "usb_dnl_fastboot", 16)) { 90c0acb0f2SFrank Wang /* Fix to Google's VID and PID */ 91c0acb0f2SFrank Wang dev->idVendor = __constant_cpu_to_le16(0x18d1); 92c0acb0f2SFrank Wang dev->idProduct = __constant_cpu_to_le16(0xd00d); 93ca422507SYifeng Zhao } else if (!strncmp(name, "usb_dnl_dfu", 11)) { 94ca422507SYifeng Zhao /* Fix to Rockchip's VID and PID for DFU */ 95ca422507SYifeng Zhao dev->idVendor = cpu_to_le16(0x2207); 96ca422507SYifeng Zhao dev->idProduct = cpu_to_le16(0x0107); 970a076251SFrank Wang } else if (!strncmp(name, "usb_dnl_ums", 11)) { 980a076251SFrank Wang dev->idVendor = cpu_to_le16(0x2207); 990a076251SFrank Wang dev->idProduct = cpu_to_le16(0x0010); 100ba437c8cSFrank Wang } 101f16e43f8SFrank Wang 102f16e43f8SFrank Wang return 0; 103f16e43f8SFrank Wang } 104f16e43f8SFrank Wang 105f16e43f8SFrank Wang __maybe_unused 106f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw) 107f16e43f8SFrank Wang { 108f16e43f8SFrank Wang assert(!cbw); 109f16e43f8SFrank Wang 110f16e43f8SFrank Wang debug("%s:\n", __func__); 111f16e43f8SFrank Wang debug("Signature %x\n", cbw->Signature); 112f16e43f8SFrank Wang debug("Tag %x\n", cbw->Tag); 113f16e43f8SFrank Wang debug("DataTransferLength %x\n", cbw->DataTransferLength); 114f16e43f8SFrank Wang debug("Flags %x\n", cbw->Flags); 115f16e43f8SFrank Wang debug("LUN %x\n", cbw->Lun); 116f16e43f8SFrank Wang debug("Length %x\n", cbw->Length); 117f16e43f8SFrank Wang debug("OptionCode %x\n", cbw->CDB[0]); 118f16e43f8SFrank Wang debug("SubCode %x\n", cbw->CDB[1]); 119f16e43f8SFrank Wang debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2])); 120f16e43f8SFrank Wang debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7])); 121f16e43f8SFrank Wang } 122f16e43f8SFrank Wang 123f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common) 124f16e43f8SFrank Wang { 125f16e43f8SFrank Wang struct fsg_lun *curlun; 126f16e43f8SFrank Wang 127f16e43f8SFrank Wang /* Check the LUN */ 128f16e43f8SFrank Wang if (common->lun >= 0 && common->lun < common->nluns) { 129f16e43f8SFrank Wang curlun = &common->luns[common->lun]; 130f16e43f8SFrank Wang if (common->cmnd[0] != SC_REQUEST_SENSE) { 131f16e43f8SFrank Wang curlun->sense_data = SS_NO_SENSE; 132f16e43f8SFrank Wang curlun->info_valid = 0; 133f16e43f8SFrank Wang } 134f16e43f8SFrank Wang } else { 135f16e43f8SFrank Wang curlun = NULL; 136f16e43f8SFrank Wang common->bad_lun_okay = 0; 137f16e43f8SFrank Wang 138f16e43f8SFrank Wang /* 139f16e43f8SFrank Wang * INQUIRY and REQUEST SENSE commands are explicitly allowed 140f16e43f8SFrank Wang * to use unsupported LUNs; all others may not. 141f16e43f8SFrank Wang */ 142f16e43f8SFrank Wang if (common->cmnd[0] != SC_INQUIRY && 143f16e43f8SFrank Wang common->cmnd[0] != SC_REQUEST_SENSE) { 144f16e43f8SFrank Wang debug("unsupported LUN %d\n", common->lun); 145f16e43f8SFrank Wang return -EINVAL; 146f16e43f8SFrank Wang } 147f16e43f8SFrank Wang } 148f16e43f8SFrank Wang 149f16e43f8SFrank Wang return 0; 150f16e43f8SFrank Wang } 151f16e43f8SFrank Wang 152f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req) 153f16e43f8SFrank Wang { 1545b081643SFrank Wang u32 boot_flag = BOOT_NORMAL; 1555b081643SFrank Wang 1565b081643SFrank Wang if (rkusb_rst_code == 0x03) 1575b081643SFrank Wang boot_flag = BOOT_BROM_DOWNLOAD; 1585b081643SFrank Wang 1595b081643SFrank Wang rkusb_rst_code = 0; /* restore to default */ 1605b081643SFrank Wang writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 161866d7966SJoseph Chen 162f16e43f8SFrank Wang do_reset(NULL, 0, 0, NULL); 163f16e43f8SFrank Wang } 164f16e43f8SFrank Wang 165f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common, 166f16e43f8SFrank Wang struct fsg_buffhd *bh) 167f16e43f8SFrank Wang { 168f16e43f8SFrank Wang common->data_size_from_cmnd = common->cmnd[4]; 169f16e43f8SFrank Wang common->residue = 0; 170f16e43f8SFrank Wang bh->inreq->complete = __do_reset; 171f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 172f16e43f8SFrank Wang 1735b081643SFrank Wang rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1]; 174f16e43f8SFrank Wang return 0; 175f16e43f8SFrank Wang } 176f16e43f8SFrank Wang 177f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common, 178f16e43f8SFrank Wang struct fsg_buffhd *bh) 179f16e43f8SFrank Wang { 1807eb64117SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 1817eb64117SJon Lin 1827eb64117SJon Lin if ((desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) || 1837eb64117SJon Lin desc->if_type == IF_TYPE_SPINOR) 1847eb64117SJon Lin common->residue = 0x03 << 24; /* 128KB Max block xfer for SPI Nor */ 1857eb64117SJon Lin else 186f16e43f8SFrank Wang common->residue = 0x06 << 24; /* Max block xfer support from host */ 1877eb64117SJon Lin 188f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 189f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 190f16e43f8SFrank Wang 191f16e43f8SFrank Wang return 0; 192f16e43f8SFrank Wang } 193f16e43f8SFrank Wang 194f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common, 195f16e43f8SFrank Wang struct fsg_buffhd *bh) 196f16e43f8SFrank Wang { 197f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 198e0023032SKever Yang u32 len = 5; 199d7386f60SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 200afc6362aSJon Lin u32 devnum = ums[common->lun].block_dev.devnum; 201afc6362aSJon Lin const char *str; 202f16e43f8SFrank Wang 203afc6362aSJon Lin switch (type) { 204afc6362aSJon Lin case IF_TYPE_MMC: 205afc6362aSJon Lin str = "EMMC "; 206afc6362aSJon Lin break; 207afc6362aSJon Lin case IF_TYPE_RKNAND: 208afc6362aSJon Lin str = "NAND "; 209afc6362aSJon Lin break; 210afc6362aSJon Lin case IF_TYPE_MTD: 211afc6362aSJon Lin if (devnum == BLK_MTD_SPI_NAND) 212afc6362aSJon Lin str ="SNAND"; 213afc6362aSJon Lin else if (devnum == BLK_MTD_NAND) 214afc6362aSJon Lin str = "NAND "; 215d7386f60SFrank Wang else 216afc6362aSJon Lin str = "NOR "; 217afc6362aSJon Lin break; 218afc6362aSJon Lin default: 219afc6362aSJon Lin str = "UNKN "; /* unknown */ 220afc6362aSJon Lin break; 221afc6362aSJon Lin } 222afc6362aSJon Lin 223afc6362aSJon Lin memcpy((void *)&buf[0], str, len); 224f16e43f8SFrank Wang 225f16e43f8SFrank Wang /* Set data xfer size */ 226f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 227e0023032SKever Yang common->data_size = len; 228f16e43f8SFrank Wang 229f16e43f8SFrank Wang return len; 230f16e43f8SFrank Wang } 231f16e43f8SFrank Wang 232f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common, 233f16e43f8SFrank Wang struct fsg_buffhd *bh) 234f16e43f8SFrank Wang { 235f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 236e0023032SKever Yang u32 len = 64; 237f16e43f8SFrank Wang 238f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 239f16e43f8SFrank Wang 240f16e43f8SFrank Wang /* Set data xfer size */ 241f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 242e0023032SKever Yang common->data_size = len; 243f16e43f8SFrank Wang 244f16e43f8SFrank Wang return len; 245f16e43f8SFrank Wang } 246f16e43f8SFrank Wang 247f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common, 248f16e43f8SFrank Wang struct fsg_buffhd *bh) 249f16e43f8SFrank Wang { 250e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 251f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 252d23ec8c4SKever Yang u32 len = sizeof(struct rk_flash_info); 253f16e43f8SFrank Wang struct rk_flash_info finfo = { 254e66d4537SJon Lin .block_size = ROCKCHIP_FLASH_BLOCK_SIZE, 255f16e43f8SFrank Wang .ecc_bits = 0, 256e66d4537SJon Lin .page_size = ROCKCHIP_FLASH_PAGE_SIZE, 257f16e43f8SFrank Wang .access_time = 40, 258f16e43f8SFrank Wang .manufacturer = 0, 259f16e43f8SFrank Wang .flash_mask = 0 260f16e43f8SFrank Wang }; 261f16e43f8SFrank Wang 262e66d4537SJon Lin finfo.flash_size = (u32)desc->lba; 263e66d4537SJon Lin 264e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD && 265e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND || 266e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) { 267e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv; 268e66d4537SJon Lin 269e66d4537SJon Lin if (mtd) { 270e66d4537SJon Lin finfo.block_size = mtd->erasesize >> 9; 271e66d4537SJon Lin finfo.page_size = mtd->writesize >> 9; 272e66d4537SJon Lin } 273e66d4537SJon Lin } 274e66d4537SJon Lin 27565a0fed9SJon Lin if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) { 27665a0fed9SJon Lin /* RV1126/RK3308 mtd spinor keep the former upgrade mode */ 27765a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308) 278b8e5601dSJon Lin finfo.block_size = 0x80; /* Aligned to 64KB */ 27965a0fed9SJon Lin #else 28065a0fed9SJon Lin finfo.block_size = ROCKCHIP_FLASH_BLOCK_SIZE; 28165a0fed9SJon Lin #endif 28265a0fed9SJon Lin } 28365a0fed9SJon Lin 284e66d4537SJon Lin debug("Flash info: block_size= %x page_size= %x\n", finfo.block_size, 285e66d4537SJon Lin finfo.page_size); 286e66d4537SJon Lin 287f16e43f8SFrank Wang if (finfo.flash_size) 288f16e43f8SFrank Wang finfo.flash_mask = 1; 289f16e43f8SFrank Wang 290f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 291f16e43f8SFrank Wang memcpy((void *)&buf[0], (void *)&finfo, len); 292f16e43f8SFrank Wang 293f16e43f8SFrank Wang /* Set data xfer size */ 294f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 295d23ec8c4SKever Yang /* legacy upgrade_tool does not set correct transfer size */ 296d23ec8c4SKever Yang common->data_size = len; 297f16e43f8SFrank Wang 298f16e43f8SFrank Wang return len; 299f16e43f8SFrank Wang } 300f16e43f8SFrank Wang 301829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common, 302829f2b85SFrank Wang struct fsg_buffhd *bh) 303829f2b85SFrank Wang { 304829f2b85SFrank Wang u8 *buf = (u8 *)bh->buf; 305829f2b85SFrank Wang u32 len = common->data_size; 306829f2b85SFrank Wang u32 chip_info[4]; 307829f2b85SFrank Wang 308829f2b85SFrank Wang memset((void *)chip_info, 0, sizeof(chip_info)); 309829f2b85SFrank Wang rockchip_rockusb_get_chip_info(chip_info); 310829f2b85SFrank Wang 311829f2b85SFrank Wang memset((void *)&buf[0], 0, len); 312829f2b85SFrank Wang memcpy((void *)&buf[0], (void *)chip_info, len); 313829f2b85SFrank Wang 314829f2b85SFrank Wang /* Set data xfer size */ 315829f2b85SFrank Wang common->residue = common->data_size_from_cmnd = len; 316829f2b85SFrank Wang 317829f2b85SFrank Wang return len; 318829f2b85SFrank Wang } 319829f2b85SFrank Wang 320f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common, 321f16e43f8SFrank Wang struct fsg_buffhd *bh) 322f16e43f8SFrank Wang { 323f16e43f8SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 324f16e43f8SFrank Wang u32 lba, amount; 325f16e43f8SFrank Wang loff_t file_offset; 326f16e43f8SFrank Wang int rc; 327f16e43f8SFrank Wang 328f16e43f8SFrank Wang lba = get_unaligned_be32(&common->cmnd[2]); 329f16e43f8SFrank Wang if (lba >= curlun->num_sectors) { 330f16e43f8SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 331f16e43f8SFrank Wang rc = -EINVAL; 332f16e43f8SFrank Wang goto out; 333f16e43f8SFrank Wang } 334f16e43f8SFrank Wang 335f16e43f8SFrank Wang file_offset = ((loff_t) lba) << 9; 336f16e43f8SFrank Wang amount = get_unaligned_be16(&common->cmnd[7]) << 9; 337f16e43f8SFrank Wang if (unlikely(amount == 0)) { 338f16e43f8SFrank Wang curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 339f16e43f8SFrank Wang rc = -EIO; 340f16e43f8SFrank Wang goto out; 341f16e43f8SFrank Wang } 342f16e43f8SFrank Wang 343f16e43f8SFrank Wang /* Perform the erase */ 344f16e43f8SFrank Wang rc = ums[common->lun].erase_sector(&ums[common->lun], 345f16e43f8SFrank Wang file_offset / SECTOR_SIZE, 346f16e43f8SFrank Wang amount / SECTOR_SIZE); 347f16e43f8SFrank Wang if (!rc) { 348f16e43f8SFrank Wang curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 349f16e43f8SFrank Wang rc = -EIO; 350f16e43f8SFrank Wang } 351f16e43f8SFrank Wang 352f16e43f8SFrank Wang out: 353f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 354f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 355f16e43f8SFrank Wang 356f16e43f8SFrank Wang return rc; 357f16e43f8SFrank Wang } 358f16e43f8SFrank Wang 359e66d4537SJon Lin static int rkusb_do_erase_force(struct fsg_common *common, 360e66d4537SJon Lin struct fsg_buffhd *bh) 361e66d4537SJon Lin { 362e66d4537SJon Lin struct blk_desc *desc = &ums[common->lun].block_dev; 363e66d4537SJon Lin struct fsg_lun *curlun = &common->luns[common->lun]; 364e66d4537SJon Lin u16 block_size = ROCKCHIP_FLASH_BLOCK_SIZE; 365e66d4537SJon Lin u32 lba, amount; 366e66d4537SJon Lin loff_t file_offset; 367e66d4537SJon Lin int rc; 368e66d4537SJon Lin 369e66d4537SJon Lin lba = get_unaligned_be32(&common->cmnd[2]); 370e66d4537SJon Lin if (lba >= curlun->num_sectors) { 371e66d4537SJon Lin curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 372e66d4537SJon Lin rc = -EINVAL; 373e66d4537SJon Lin goto out; 374e66d4537SJon Lin } 375e66d4537SJon Lin 376e66d4537SJon Lin if (desc->if_type == IF_TYPE_MTD && 377e66d4537SJon Lin (desc->devnum == BLK_MTD_NAND || 378e66d4537SJon Lin desc->devnum == BLK_MTD_SPI_NAND)) { 379e66d4537SJon Lin struct mtd_info *mtd = (struct mtd_info *)desc->bdev->priv; 380e66d4537SJon Lin 381e66d4537SJon Lin if (mtd) 382e66d4537SJon Lin block_size = mtd->erasesize >> 9; 383e66d4537SJon Lin } 384e66d4537SJon Lin 385e66d4537SJon Lin file_offset = ((loff_t)lba) * block_size; 386e66d4537SJon Lin amount = get_unaligned_be16(&common->cmnd[7]) * block_size; 387e66d4537SJon Lin 388e66d4537SJon Lin debug("%s lba= %x, nsec= %x\n", __func__, lba, 389e66d4537SJon Lin (u32)get_unaligned_be16(&common->cmnd[7])); 390e66d4537SJon Lin 391e66d4537SJon Lin if (unlikely(amount == 0)) { 392e66d4537SJon Lin curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 393e66d4537SJon Lin rc = -EIO; 394e66d4537SJon Lin goto out; 395e66d4537SJon Lin } 396e66d4537SJon Lin 397e66d4537SJon Lin /* Perform the erase */ 398e66d4537SJon Lin rc = ums[common->lun].erase_sector(&ums[common->lun], 399e66d4537SJon Lin file_offset, 400e66d4537SJon Lin amount); 401e66d4537SJon Lin if (!rc) { 402e66d4537SJon Lin curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 403e66d4537SJon Lin rc = -EIO; 404e66d4537SJon Lin } 405e66d4537SJon Lin 406e66d4537SJon Lin out: 407e66d4537SJon Lin common->data_dir = DATA_DIR_NONE; 408e66d4537SJon Lin bh->state = BUF_STATE_EMPTY; 409e66d4537SJon Lin 410e66d4537SJon Lin return rc; 411e66d4537SJon Lin } 412e66d4537SJon Lin 4130d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 4140d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common) 4150d0c3248SFrank Wang { 4160d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 4170d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 4180d0c3248SFrank Wang struct vendor_item *vhead; 4190d0c3248SFrank Wang struct fsg_buffhd *bh; 4200d0c3248SFrank Wang void *data; 4210d0c3248SFrank Wang int rc; 4220d0c3248SFrank Wang 4230d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 4240d0c3248SFrank Wang /* _MUST_ small than 64K */ 4250d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 4260d0c3248SFrank Wang return -EINVAL; 4270d0c3248SFrank Wang } 4280d0c3248SFrank Wang 4290d0c3248SFrank Wang common->residue = common->data_size; 4300d0c3248SFrank Wang common->usb_amount_left = common->data_size; 4310d0c3248SFrank Wang 4320d0c3248SFrank Wang /* Carry out the file writes */ 4330d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 4340d0c3248SFrank Wang return -EIO; /* No data to write */ 4350d0c3248SFrank Wang 4360d0c3248SFrank Wang for (;;) { 4370d0c3248SFrank Wang if (common->usb_amount_left > 0) { 4380d0c3248SFrank Wang /* Wait for the next buffer to become available */ 4390d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 4400d0c3248SFrank Wang if (bh->state != BUF_STATE_EMPTY) 4410d0c3248SFrank Wang goto wait; 4420d0c3248SFrank Wang 4430d0c3248SFrank Wang /* Request the next buffer */ 4440d0c3248SFrank Wang common->usb_amount_left -= common->data_size; 4450d0c3248SFrank Wang bh->outreq->length = common->data_size; 4460d0c3248SFrank Wang bh->bulk_out_intended_length = common->data_size; 4470d0c3248SFrank Wang bh->outreq->short_not_ok = 1; 4480d0c3248SFrank Wang 4490d0c3248SFrank Wang START_TRANSFER_OR(common, bulk_out, bh->outreq, 4500d0c3248SFrank Wang &bh->outreq_busy, &bh->state) 4510d0c3248SFrank Wang /* 4520d0c3248SFrank Wang * Don't know what to do if 4530d0c3248SFrank Wang * common->fsg is NULL 4540d0c3248SFrank Wang */ 4550d0c3248SFrank Wang return -EIO; 4560d0c3248SFrank Wang common->next_buffhd_to_fill = bh->next; 4570d0c3248SFrank Wang } else { 4580d0c3248SFrank Wang /* Then, wait for the data to become available */ 4590d0c3248SFrank Wang bh = common->next_buffhd_to_drain; 4600d0c3248SFrank Wang if (bh->state != BUF_STATE_FULL) 4610d0c3248SFrank Wang goto wait; 4620d0c3248SFrank Wang 4630d0c3248SFrank Wang common->next_buffhd_to_drain = bh->next; 4640d0c3248SFrank Wang bh->state = BUF_STATE_EMPTY; 4650d0c3248SFrank Wang 4660d0c3248SFrank Wang /* Did something go wrong with the transfer? */ 4670d0c3248SFrank Wang if (bh->outreq->status != 0) { 4680d0c3248SFrank Wang curlun->sense_data = SS_COMMUNICATION_FAILURE; 4690d0c3248SFrank Wang curlun->info_valid = 1; 4700d0c3248SFrank Wang break; 4710d0c3248SFrank Wang } 4720d0c3248SFrank Wang 4730d0c3248SFrank Wang /* Perform the write */ 4740d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 4750d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 4760d0c3248SFrank Wang 4770d0c3248SFrank Wang if (!type) { 478420ee9d5SJoseph Chen if (vhead->id == HDCP_14_HDMI_ID || 47978dcc928SZhang Yubing vhead->id == HDCP_14_HDMIRX_ID || 48078dcc928SZhang Yubing vhead->id == HDCP_14_DP_ID) { 481420ee9d5SJoseph Chen rc = vendor_handle_hdcp(vhead); 482420ee9d5SJoseph Chen if (rc < 0) { 483420ee9d5SJoseph Chen curlun->sense_data = SS_WRITE_ERROR; 484420ee9d5SJoseph Chen return -EIO; 485420ee9d5SJoseph Chen } 486420ee9d5SJoseph Chen } 487420ee9d5SJoseph Chen 4880d0c3248SFrank Wang /* Vendor storage */ 4890d0c3248SFrank Wang rc = vendor_storage_write(vhead->id, 4900d0c3248SFrank Wang (char __user *)data, 4910d0c3248SFrank Wang vhead->size); 49219652be0SFrank Wang if (rc < 0) { 49319652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 4940d0c3248SFrank Wang return -EIO; 49519652be0SFrank Wang } 4962122174dSWu Liangqing } else if (type == 1) { 4970d0c3248SFrank Wang /* RPMB */ 4986f0347c8Stony.xu rc = 4996f0347c8Stony.xu write_keybox_to_secure_storage((u8 *)data, 5006f0347c8Stony.xu vhead->size); 50119652be0SFrank Wang if (rc < 0) { 50219652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 5036f0347c8Stony.xu return -EIO; 5040d0c3248SFrank Wang } 5052122174dSWu Liangqing } else if (type == 2) { 5062122174dSWu Liangqing /* security storage */ 5072122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER 5082122174dSWu Liangqing debug("%s call rk_avb_write_perm_attr %d, %d\n", 5092122174dSWu Liangqing __func__, vhead->id, vhead->size); 5102122174dSWu Liangqing rc = rk_avb_write_perm_attr(vhead->id, 5112122174dSWu Liangqing (char __user *)data, 5122122174dSWu Liangqing vhead->size); 5132122174dSWu Liangqing if (rc < 0) { 5142122174dSWu Liangqing curlun->sense_data = SS_WRITE_ERROR; 5152122174dSWu Liangqing return -EIO; 5162122174dSWu Liangqing } 5172122174dSWu Liangqing #else 5182122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER\n"); 5192122174dSWu Liangqing #endif 520850ced9dSHisping Lin } else if (type == 3) { 521850ced9dSHisping Lin /* efuse or otp*/ 522850ced9dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT 523850ced9dSHisping Lin if (memcmp(data, "TAEK", 4) == 0) { 524850ced9dSHisping Lin if (vhead->size - 8 != 32) { 525850ced9dSHisping Lin printf("check ta encryption key size fail!\n"); 526850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 527850ced9dSHisping Lin return -EIO; 528850ced9dSHisping Lin } 529850ced9dSHisping Lin if (trusty_write_ta_encryption_key((uint32_t *)(data + 8), 8) != 0) { 530850ced9dSHisping Lin printf("trusty_write_ta_encryption_key error!"); 531850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 532850ced9dSHisping Lin return -EIO; 533850ced9dSHisping Lin } 534a43611afSHisping Lin } else if (memcmp(data, "EHUK", 4) == 0) { 535a43611afSHisping Lin if (vhead->size - 8 != 32) { 536a43611afSHisping Lin printf("check oem huk size fail!\n"); 537a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 538a43611afSHisping Lin return -EIO; 539a43611afSHisping Lin } 540a43611afSHisping Lin if (trusty_write_oem_huk((uint32_t *)(data + 8), 8) != 0) { 541a43611afSHisping Lin printf("trusty_write_oem_huk error!"); 542a43611afSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 543a43611afSHisping Lin return -EIO; 544a43611afSHisping Lin } 545850ced9dSHisping Lin } else { 546850ced9dSHisping Lin printf("Unknown tag\n"); 547850ced9dSHisping Lin curlun->sense_data = SS_WRITE_ERROR; 548850ced9dSHisping Lin return -EIO; 549850ced9dSHisping Lin } 550850ced9dSHisping Lin #else 551850ced9dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n"); 552850ced9dSHisping Lin #endif 5532122174dSWu Liangqing } else { 5542122174dSWu Liangqing return -EINVAL; 55519652be0SFrank Wang } 5560d0c3248SFrank Wang 5570d0c3248SFrank Wang common->residue -= common->data_size; 5580d0c3248SFrank Wang 5590d0c3248SFrank Wang /* Did the host decide to stop early? */ 5600d0c3248SFrank Wang if (bh->outreq->actual != bh->outreq->length) 5610d0c3248SFrank Wang common->short_packet_received = 1; 5620d0c3248SFrank Wang break; /* Command done */ 5630d0c3248SFrank Wang } 5640d0c3248SFrank Wang wait: 5650d0c3248SFrank Wang /* Wait for something to happen */ 5660d0c3248SFrank Wang rc = sleep_thread(common); 5670d0c3248SFrank Wang if (rc) 5680d0c3248SFrank Wang return rc; 5690d0c3248SFrank Wang } 5700d0c3248SFrank Wang 5710d0c3248SFrank Wang return -EIO; /* No default reply */ 5720d0c3248SFrank Wang } 5730d0c3248SFrank Wang 5740d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common) 5750d0c3248SFrank Wang { 5760d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 5770d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 5780d0c3248SFrank Wang struct vendor_item *vhead; 5790d0c3248SFrank Wang struct fsg_buffhd *bh; 5800d0c3248SFrank Wang void *data; 5810d0c3248SFrank Wang int rc; 5820d0c3248SFrank Wang 5830d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 5840d0c3248SFrank Wang /* _MUST_ small than 64K */ 5850d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 5860d0c3248SFrank Wang return -EINVAL; 5870d0c3248SFrank Wang } 5880d0c3248SFrank Wang 5890d0c3248SFrank Wang common->residue = common->data_size; 5900d0c3248SFrank Wang common->usb_amount_left = common->data_size; 5910d0c3248SFrank Wang 5920d0c3248SFrank Wang /* Carry out the file reads */ 5930d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 5940d0c3248SFrank Wang return -EIO; /* No default reply */ 5950d0c3248SFrank Wang 5960d0c3248SFrank Wang for (;;) { 5970d0c3248SFrank Wang /* Wait for the next buffer to become available */ 5980d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 5990d0c3248SFrank Wang while (bh->state != BUF_STATE_EMPTY) { 6000d0c3248SFrank Wang rc = sleep_thread(common); 6010d0c3248SFrank Wang if (rc) 6020d0c3248SFrank Wang return rc; 6030d0c3248SFrank Wang } 6040d0c3248SFrank Wang 6050d0c3248SFrank Wang memset(bh->buf, 0, FSG_BUFLEN); 6060d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 6070d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 6080d0c3248SFrank Wang vhead->id = get_unaligned_be16(&common->cmnd[2]); 6090d0c3248SFrank Wang 6100d0c3248SFrank Wang if (!type) { 6110d0c3248SFrank Wang /* Vendor storage */ 6120d0c3248SFrank Wang rc = vendor_storage_read(vhead->id, 6130d0c3248SFrank Wang (char __user *)data, 6140d0c3248SFrank Wang common->data_size); 61519652be0SFrank Wang if (!rc) { 61619652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 6170d0c3248SFrank Wang return -EIO; 61819652be0SFrank Wang } 6190d0c3248SFrank Wang vhead->size = rc; 6202122174dSWu Liangqing } else if (type == 1) { 6210d0c3248SFrank Wang /* RPMB */ 622700a3668STony Xu rc = 623700a3668STony Xu read_raw_data_from_secure_storage((u8 *)data, 624700a3668STony Xu common->data_size); 62519652be0SFrank Wang if (!rc) { 62619652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 627700a3668STony Xu return -EIO; 62819652be0SFrank Wang } 629700a3668STony Xu vhead->size = rc; 6302122174dSWu Liangqing } else if (type == 2) { 6312122174dSWu Liangqing /* security storage */ 6322122174dSWu Liangqing #ifdef CONFIG_RK_AVB_LIBAVB_USER 6332122174dSWu Liangqing rc = rk_avb_read_perm_attr(vhead->id, 6342122174dSWu Liangqing (char __user *)data, 6352122174dSWu Liangqing vhead->size); 6362122174dSWu Liangqing if (rc < 0) 6372122174dSWu Liangqing return -EIO; 6382122174dSWu Liangqing vhead->size = rc; 6392122174dSWu Liangqing #else 6402122174dSWu Liangqing printf("Please enable CONFIG_RK_AVB_LIBAVB_USER!\n"); 6412122174dSWu Liangqing #endif 642*47c8f13dSHisping Lin } else if (type == 3) { 643*47c8f13dSHisping Lin /* efuse or otp*/ 644*47c8f13dSHisping Lin #ifdef CONFIG_OPTEE_CLIENT 645*47c8f13dSHisping Lin if (vhead->id == 120) { 646*47c8f13dSHisping Lin u8 value; 647*47c8f13dSHisping Lin char *written_str = "key is written!"; 648*47c8f13dSHisping Lin char *not_written_str = "key is not written!"; 649*47c8f13dSHisping Lin if (trusty_ta_encryption_key_is_written(&value) != 0) { 650*47c8f13dSHisping Lin printf("trusty_ta_encryption_key_is_written error!"); 651*47c8f13dSHisping Lin return -EIO; 652*47c8f13dSHisping Lin } 653*47c8f13dSHisping Lin if (value) { 654*47c8f13dSHisping Lin memcpy(data, written_str, strlen(written_str)); 655*47c8f13dSHisping Lin vhead->size = strlen(written_str); 656*47c8f13dSHisping Lin } else { 657*47c8f13dSHisping Lin memcpy(data, not_written_str, strlen(not_written_str)); 658*47c8f13dSHisping Lin vhead->size = strlen(not_written_str); 659*47c8f13dSHisping Lin } 660*47c8f13dSHisping Lin } else { 661*47c8f13dSHisping Lin printf("Unknown tag\n"); 662*47c8f13dSHisping Lin return -EIO; 663*47c8f13dSHisping Lin } 664*47c8f13dSHisping Lin #else 665*47c8f13dSHisping Lin printf("Please enable CONFIG_OPTEE_CLIENT\n"); 666*47c8f13dSHisping Lin #endif 6672122174dSWu Liangqing } else { 6682122174dSWu Liangqing return -EINVAL; 6690d0c3248SFrank Wang } 6700d0c3248SFrank Wang 6710d0c3248SFrank Wang common->residue -= common->data_size; 6720d0c3248SFrank Wang bh->inreq->length = common->data_size; 6730d0c3248SFrank Wang bh->state = BUF_STATE_FULL; 6740d0c3248SFrank Wang 6750d0c3248SFrank Wang break; /* No more left to read */ 6760d0c3248SFrank Wang } 6770d0c3248SFrank Wang 6780d0c3248SFrank Wang return -EIO; /* No default reply */ 6790d0c3248SFrank Wang } 6800d0c3248SFrank Wang #endif 6810d0c3248SFrank Wang 682d4cce25eSYifeng Zhao static int rkusb_do_get_storage_info(struct fsg_common *common, 683d4cce25eSYifeng Zhao struct fsg_buffhd *bh) 684d4cce25eSYifeng Zhao { 685d4cce25eSYifeng Zhao enum if_type type = ums[common->lun].block_dev.if_type; 686d4cce25eSYifeng Zhao int devnum = ums[common->lun].block_dev.devnum; 687d4cce25eSYifeng Zhao u32 media = BOOT_TYPE_UNKNOWN; 688d4cce25eSYifeng Zhao u32 len = common->data_size; 689d4cce25eSYifeng Zhao u8 *buf = (u8 *)bh->buf; 690d4cce25eSYifeng Zhao 691d4cce25eSYifeng Zhao if (len > 4) 692d4cce25eSYifeng Zhao len = 4; 693d4cce25eSYifeng Zhao 694d4cce25eSYifeng Zhao switch (type) { 695d4cce25eSYifeng Zhao case IF_TYPE_MMC: 696d4cce25eSYifeng Zhao media = BOOT_TYPE_EMMC; 697d4cce25eSYifeng Zhao break; 698d4cce25eSYifeng Zhao 699d4cce25eSYifeng Zhao case IF_TYPE_SD: 700d4cce25eSYifeng Zhao media = BOOT_TYPE_SD0; 701d4cce25eSYifeng Zhao break; 702d4cce25eSYifeng Zhao 703d4cce25eSYifeng Zhao case IF_TYPE_MTD: 704d4cce25eSYifeng Zhao if (devnum == BLK_MTD_SPI_NAND) 705d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NAND; 706d4cce25eSYifeng Zhao else if (devnum == BLK_MTD_NAND) 707d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND; 708d4cce25eSYifeng Zhao else 709d4cce25eSYifeng Zhao media = BOOT_TYPE_MTD_BLK_SPI_NOR; 710d4cce25eSYifeng Zhao break; 711d4cce25eSYifeng Zhao 712d4cce25eSYifeng Zhao case IF_TYPE_SCSI: 713d4cce25eSYifeng Zhao media = BOOT_TYPE_SATA; 714d4cce25eSYifeng Zhao break; 715d4cce25eSYifeng Zhao 716d4cce25eSYifeng Zhao case IF_TYPE_RKNAND: 717d4cce25eSYifeng Zhao media = BOOT_TYPE_NAND; 718d4cce25eSYifeng Zhao break; 7192daa60eeSJon Lin 7202daa60eeSJon Lin case IF_TYPE_NVME: 7212daa60eeSJon Lin media = BOOT_TYPE_PCIE; 7222daa60eeSJon Lin break; 7232daa60eeSJon Lin 724d4cce25eSYifeng Zhao default: 725d4cce25eSYifeng Zhao break; 726d4cce25eSYifeng Zhao } 727d4cce25eSYifeng Zhao 728d4cce25eSYifeng Zhao memcpy((void *)&buf[0], (void *)&media, len); 729d4cce25eSYifeng Zhao common->residue = len; 730d4cce25eSYifeng Zhao common->data_size_from_cmnd = len; 731d4cce25eSYifeng Zhao 732d4cce25eSYifeng Zhao return len; 733d4cce25eSYifeng Zhao } 734d4cce25eSYifeng Zhao 735f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common, 736f16e43f8SFrank Wang struct fsg_buffhd *bh) 737f16e43f8SFrank Wang { 738f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 739f16e43f8SFrank Wang u32 len = common->data_size; 740d015bf41SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 741e66d4537SJon Lin int devnum = ums[common->lun].block_dev.devnum; 742f16e43f8SFrank Wang 743f16e43f8SFrank Wang /* 744f16e43f8SFrank Wang * bit[0]: Direct LBA, 0: Disabled; 7450d0c3248SFrank Wang * bit[1]: Vendor Storage API, 0: Disabed (default); 746d015bf41SFrank Wang * bit[2]: First 4M Access, 0: Disabled; 7470d0c3248SFrank Wang * bit[3]: Read LBA On, 0: Disabed (default); 7480d0c3248SFrank Wang * bit[4]: New Vendor Storage API, 0: Disabed; 749d4cce25eSYifeng Zhao * bit[5]: Read uart data from ram 750d4cce25eSYifeng Zhao * bit[6]: Read IDB config 751d4cce25eSYifeng Zhao * bit[7]: Read SecureMode 752d4cce25eSYifeng Zhao * bit[8]: New IDB feature 753d4cce25eSYifeng Zhao * bit[9]: Get storage media info 754d4cce25eSYifeng Zhao * bit[10:63}: Reserved. 755f16e43f8SFrank Wang */ 756f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 7572daa60eeSJon Lin if (type == IF_TYPE_MMC || type == IF_TYPE_SD || type == IF_TYPE_NVME) 7580d0c3248SFrank Wang buf[0] = BIT(0) | BIT(2) | BIT(4); 7590d0c3248SFrank Wang else 7600d0c3248SFrank Wang buf[0] = BIT(0) | BIT(4); 761f16e43f8SFrank Wang 762e66d4537SJon Lin if (type == IF_TYPE_MTD && 763e66d4537SJon Lin (devnum == BLK_MTD_NAND || 764e66d4537SJon Lin devnum == BLK_MTD_SPI_NAND)) 765e66d4537SJon Lin buf[0] |= (1 << 6); 766e66d4537SJon Lin 76765a0fed9SJon Lin #if !defined(CONFIG_ROCKCHIP_RV1126) && !defined(CONFIG_ROCKCHIP_RK3308) 76865a0fed9SJon Lin if (type == IF_TYPE_MTD && devnum == BLK_MTD_SPI_NOR) 76965a0fed9SJon Lin buf[0] |= (1 << 6); 77065a0fed9SJon Lin #endif 77165a0fed9SJon Lin 7720b97a2cbSJoseph Chen #if defined(CONFIG_ROCKCHIP_NEW_IDB) 773007849d8SYifeng Zhao buf[1] = BIT(0); 774007849d8SYifeng Zhao #endif 7752c0c66c1SYifeng Zhao buf[1] |= BIT(1); /* Switch Storage */ 7762c0c66c1SYifeng Zhao buf[1] |= BIT(2); /* LBAwrite Parity */ 777d4cce25eSYifeng Zhao 778f16e43f8SFrank Wang /* Set data xfer size */ 779e66d4537SJon Lin common->residue = len; 780e66d4537SJon Lin common->data_size_from_cmnd = len; 781f16e43f8SFrank Wang 782f16e43f8SFrank Wang return len; 783f16e43f8SFrank Wang } 784f16e43f8SFrank Wang 785d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common, 786d23ec8c4SKever Yang struct fsg_buffhd *bh) 787d23ec8c4SKever Yang { 788d23ec8c4SKever Yang struct usb_request *req = bh->outreq; 789d23ec8c4SKever Yang struct fsg_bulk_cb_wrap *cbw = req->buf; 790d23ec8c4SKever Yang 791d23ec8c4SKever Yang /* FIXME cbw.DataTransferLength was not set by Upgrade Tool */ 792d23ec8c4SKever Yang common->data_size = le32_to_cpu(cbw->DataTransferLength); 793d23ec8c4SKever Yang if (common->data_size == 0) { 794d23ec8c4SKever Yang common->data_size = 795d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]) << 9; 796d23ec8c4SKever Yang printf("Trasfer Length NOT set, please use new version tool\n"); 797d23ec8c4SKever Yang debug("%s %d, cmnd1 %x\n", __func__, 798d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]), 799d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[1])); 800d23ec8c4SKever Yang } 801d23ec8c4SKever Yang if (cbw->Flags & USB_BULK_IN_FLAG) 802d23ec8c4SKever Yang common->data_dir = DATA_DIR_TO_HOST; 803d23ec8c4SKever Yang else 804d23ec8c4SKever Yang common->data_dir = DATA_DIR_FROM_HOST; 805d23ec8c4SKever Yang 806d23ec8c4SKever Yang /* Not support */ 807d23ec8c4SKever Yang common->cmnd[1] = 0; 808d23ec8c4SKever Yang } 809d23ec8c4SKever Yang 810f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common, 811f16e43f8SFrank Wang struct fsg_buffhd *bh, int *reply) 812f16e43f8SFrank Wang { 813f16e43f8SFrank Wang struct usb_request *req = bh->outreq; 814f16e43f8SFrank Wang struct fsg_bulk_cb_wrap *cbw = req->buf; 815f16e43f8SFrank Wang int rc; 816f16e43f8SFrank Wang 817f16e43f8SFrank Wang dump_cbw(cbw); 818f16e43f8SFrank Wang 819f16e43f8SFrank Wang if (rkusb_check_lun(common)) { 820f16e43f8SFrank Wang *reply = -EINVAL; 821f16e43f8SFrank Wang return RKUSB_RC_ERROR; 822f16e43f8SFrank Wang } 823f16e43f8SFrank Wang 824f16e43f8SFrank Wang switch (common->cmnd[0]) { 825f16e43f8SFrank Wang case RKUSB_TEST_UNIT_READY: 826f16e43f8SFrank Wang *reply = rkusb_do_test_unit_ready(common, bh); 827f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 828f16e43f8SFrank Wang break; 829f16e43f8SFrank Wang 830f16e43f8SFrank Wang case RKUSB_READ_FLASH_ID: 831f16e43f8SFrank Wang *reply = rkusb_do_read_flash_id(common, bh); 832f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 833f16e43f8SFrank Wang break; 834f16e43f8SFrank Wang 835f16e43f8SFrank Wang case RKUSB_TEST_BAD_BLOCK: 836f16e43f8SFrank Wang *reply = rkusb_do_test_bad_block(common, bh); 837f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 838f16e43f8SFrank Wang break; 839f16e43f8SFrank Wang 840e66d4537SJon Lin case RKUSB_ERASE_10_FORCE: 841e66d4537SJon Lin *reply = rkusb_do_erase_force(common, bh); 842e66d4537SJon Lin rc = RKUSB_RC_FINISHED; 843e66d4537SJon Lin break; 844e66d4537SJon Lin 845f16e43f8SFrank Wang case RKUSB_LBA_READ_10: 8465fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 847f16e43f8SFrank Wang common->cmnd[0] = SC_READ_10; 848f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 849f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 850f16e43f8SFrank Wang break; 851f16e43f8SFrank Wang 852f16e43f8SFrank Wang case RKUSB_LBA_WRITE_10: 8535fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 854f16e43f8SFrank Wang common->cmnd[0] = SC_WRITE_10; 855f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 856f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 857f16e43f8SFrank Wang break; 858f16e43f8SFrank Wang 859f16e43f8SFrank Wang case RKUSB_READ_FLASH_INFO: 860f16e43f8SFrank Wang *reply = rkusb_do_read_flash_info(common, bh); 861f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 862f16e43f8SFrank Wang break; 863f16e43f8SFrank Wang 864829f2b85SFrank Wang case RKUSB_GET_CHIP_VER: 865829f2b85SFrank Wang *reply = rkusb_do_get_chip_info(common, bh); 866829f2b85SFrank Wang rc = RKUSB_RC_FINISHED; 867829f2b85SFrank Wang break; 868829f2b85SFrank Wang 869f16e43f8SFrank Wang case RKUSB_LBA_ERASE: 870f16e43f8SFrank Wang *reply = rkusb_do_lba_erase(common, bh); 871f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 872f16e43f8SFrank Wang break; 873f16e43f8SFrank Wang 8740d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 8750d0c3248SFrank Wang case RKUSB_VS_WRITE: 8760d0c3248SFrank Wang *reply = rkusb_do_vs_write(common); 8770d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 8780d0c3248SFrank Wang break; 8790d0c3248SFrank Wang 8800d0c3248SFrank Wang case RKUSB_VS_READ: 8810d0c3248SFrank Wang *reply = rkusb_do_vs_read(common); 8820d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 8830d0c3248SFrank Wang break; 8840d0c3248SFrank Wang #endif 885d4cce25eSYifeng Zhao case RKUSB_GET_STORAGE_MEDIA: 886d4cce25eSYifeng Zhao *reply = rkusb_do_get_storage_info(common, bh); 887d4cce25eSYifeng Zhao rc = RKUSB_RC_FINISHED; 888d4cce25eSYifeng Zhao break; 8890d0c3248SFrank Wang 890f16e43f8SFrank Wang case RKUSB_READ_CAPACITY: 891f16e43f8SFrank Wang *reply = rkusb_do_read_capacity(common, bh); 892f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 893f16e43f8SFrank Wang break; 894f16e43f8SFrank Wang 895f16e43f8SFrank Wang case RKUSB_RESET: 896f16e43f8SFrank Wang *reply = rkusb_do_reset(common, bh); 897f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 898f16e43f8SFrank Wang break; 899f16e43f8SFrank Wang 900f16e43f8SFrank Wang case RKUSB_READ_10: 901f16e43f8SFrank Wang case RKUSB_WRITE_10: 902e0023032SKever Yang printf("CMD Not support, pls use new version Tool\n"); 903e0023032SKever Yang case RKUSB_SET_DEVICE_ID: 904f16e43f8SFrank Wang case RKUSB_ERASE_10: 905f16e43f8SFrank Wang case RKUSB_WRITE_SPARE: 906f16e43f8SFrank Wang case RKUSB_READ_SPARE: 907f16e43f8SFrank Wang case RKUSB_GET_VERSION: 908f16e43f8SFrank Wang case RKUSB_ERASE_SYS_DISK: 909f16e43f8SFrank Wang case RKUSB_SDRAM_READ_10: 910f16e43f8SFrank Wang case RKUSB_SDRAM_WRITE_10: 911f16e43f8SFrank Wang case RKUSB_SDRAM_EXECUTE: 912f16e43f8SFrank Wang case RKUSB_LOW_FORMAT: 913f16e43f8SFrank Wang case RKUSB_SET_RESET_FLAG: 914f16e43f8SFrank Wang case RKUSB_SPI_READ_10: 915f16e43f8SFrank Wang case RKUSB_SPI_WRITE_10: 916f16e43f8SFrank Wang case RKUSB_SESSION: 917f16e43f8SFrank Wang /* Fall through */ 918f16e43f8SFrank Wang default: 919f16e43f8SFrank Wang rc = RKUSB_RC_UNKNOWN_CMND; 920f16e43f8SFrank Wang break; 921f16e43f8SFrank Wang } 922f16e43f8SFrank Wang 923f16e43f8SFrank Wang return rc; 924f16e43f8SFrank Wang } 925f16e43f8SFrank Wang 9262c0c66c1SYifeng Zhao int rkusb_do_check_parity(struct fsg_common *common) 9272c0c66c1SYifeng Zhao { 9282c0c66c1SYifeng Zhao int ret = 0, rc; 9292c0c66c1SYifeng Zhao u32 parity, i, usb_parity, lba, len; 9302c0c66c1SYifeng Zhao static u32 usb_check_buffer[1024 * 256]; 9312c0c66c1SYifeng Zhao 9322c0c66c1SYifeng Zhao usb_parity = common->cmnd[9] | (common->cmnd[10] << 8) | 9332c0c66c1SYifeng Zhao (common->cmnd[11] << 16) | (common->cmnd[12] << 24); 9342c0c66c1SYifeng Zhao 9352c0c66c1SYifeng Zhao if (common->cmnd[0] == SC_WRITE_10 && (usb_parity)) { 9362c0c66c1SYifeng Zhao lba = get_unaligned_be32(&common->cmnd[2]); 9372c0c66c1SYifeng Zhao len = common->data_size_from_cmnd >> 9; 9382c0c66c1SYifeng Zhao rc = blk_dread(&ums[common->lun].block_dev, lba, len, usb_check_buffer); 9392c0c66c1SYifeng Zhao parity = 0x000055aa; 9402c0c66c1SYifeng Zhao for (i = 0; i < len * 128; i++) 9412c0c66c1SYifeng Zhao parity += usb_check_buffer[i]; 9422c0c66c1SYifeng Zhao if (!rc || parity != usb_parity) 9432c0c66c1SYifeng Zhao common->phase_error = 1; 9442c0c66c1SYifeng Zhao } 9452c0c66c1SYifeng Zhao 9462c0c66c1SYifeng Zhao return ret; 9472c0c66c1SYifeng Zhao } 9482c0c66c1SYifeng Zhao 949f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add); 950