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