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> 120d0c3248SFrank Wang 130d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 140d0c3248SFrank Wang #include <asm/arch/vendor.h> 150d0c3248SFrank Wang #endif 160d0c3248SFrank Wang 17f16e43f8SFrank Wang #include <rockusb.h> 18f16e43f8SFrank Wang 19f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_CLASS 0xff 20f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_SUB_CLASS 0x06 21f16e43f8SFrank Wang #define ROCKUSB_INTERFACE_PROTOCOL 0x05 22f16e43f8SFrank Wang 23f16e43f8SFrank Wang static struct usb_interface_descriptor rkusb_intf_desc = { 24f16e43f8SFrank Wang .bLength = USB_DT_INTERFACE_SIZE, 25f16e43f8SFrank Wang .bDescriptorType = USB_DT_INTERFACE, 26f16e43f8SFrank Wang .bInterfaceNumber = 0x00, 27f16e43f8SFrank Wang .bAlternateSetting = 0x00, 28f16e43f8SFrank Wang .bNumEndpoints = 0x02, 29f16e43f8SFrank Wang .bInterfaceClass = ROCKUSB_INTERFACE_CLASS, 30f16e43f8SFrank Wang .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS, 31f16e43f8SFrank Wang .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL, 32f16e43f8SFrank Wang }; 33f16e43f8SFrank Wang 34f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_fs_function[] = { 35f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc, 36f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_in_desc, 37f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_fs_bulk_out_desc, 38f16e43f8SFrank Wang NULL, 39f16e43f8SFrank Wang }; 40f16e43f8SFrank Wang 41f16e43f8SFrank Wang static struct usb_descriptor_header *rkusb_hs_function[] = { 42f16e43f8SFrank Wang (struct usb_descriptor_header *)&rkusb_intf_desc, 43f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_in_desc, 44f16e43f8SFrank Wang (struct usb_descriptor_header *)&fsg_hs_bulk_out_desc, 45f16e43f8SFrank Wang NULL, 46f16e43f8SFrank Wang }; 47f16e43f8SFrank Wang 4826dd3474SWilliam Wu static struct usb_descriptor_header *rkusb_ss_function[] = { 4926dd3474SWilliam Wu (struct usb_descriptor_header *)&rkusb_intf_desc, 5026dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_desc, 5126dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_in_comp_desc, 5226dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_desc, 5326dd3474SWilliam Wu (struct usb_descriptor_header *)&fsg_ss_bulk_out_comp_desc, 5426dd3474SWilliam Wu NULL, 5526dd3474SWilliam Wu }; 5626dd3474SWilliam Wu 57f16e43f8SFrank Wang struct rk_flash_info { 58f16e43f8SFrank Wang u32 flash_size; 59f16e43f8SFrank Wang u16 block_size; 60f16e43f8SFrank Wang u8 page_size; 61f16e43f8SFrank Wang u8 ecc_bits; 62f16e43f8SFrank Wang u8 access_time; 63f16e43f8SFrank Wang u8 manufacturer; 64f16e43f8SFrank Wang u8 flash_mask; 65f16e43f8SFrank Wang } __packed; 66f16e43f8SFrank Wang 675b081643SFrank Wang static int rkusb_rst_code; /* The subcode in reset command (0xFF) */ 685b081643SFrank Wang 69f16e43f8SFrank Wang int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) 70f16e43f8SFrank Wang { 71ba437c8cSFrank Wang if (IS_RKUSB_UMS_DNL(name)) { 72c0acb0f2SFrank Wang /* Fix to Rockchip's VID and PID */ 73ba437c8cSFrank Wang dev->idVendor = __constant_cpu_to_le16(0x2207); 74ba437c8cSFrank Wang dev->idProduct = __constant_cpu_to_le16(CONFIG_ROCKUSB_G_DNL_PID); 75ba437c8cSFrank Wang 76f16e43f8SFrank Wang /* Enumerate as a loader device */ 77f16e43f8SFrank Wang dev->bcdUSB = cpu_to_le16(0x0201); 78c0acb0f2SFrank Wang } else if (!strncmp(name, "usb_dnl_fastboot", 16)) { 79c0acb0f2SFrank Wang /* Fix to Google's VID and PID */ 80c0acb0f2SFrank Wang dev->idVendor = __constant_cpu_to_le16(0x18d1); 81c0acb0f2SFrank Wang dev->idProduct = __constant_cpu_to_le16(0xd00d); 82ba437c8cSFrank Wang } 83f16e43f8SFrank Wang 84f16e43f8SFrank Wang return 0; 85f16e43f8SFrank Wang } 86f16e43f8SFrank Wang 87f16e43f8SFrank Wang __maybe_unused 88f16e43f8SFrank Wang static inline void dump_cbw(struct fsg_bulk_cb_wrap *cbw) 89f16e43f8SFrank Wang { 90f16e43f8SFrank Wang assert(!cbw); 91f16e43f8SFrank Wang 92f16e43f8SFrank Wang debug("%s:\n", __func__); 93f16e43f8SFrank Wang debug("Signature %x\n", cbw->Signature); 94f16e43f8SFrank Wang debug("Tag %x\n", cbw->Tag); 95f16e43f8SFrank Wang debug("DataTransferLength %x\n", cbw->DataTransferLength); 96f16e43f8SFrank Wang debug("Flags %x\n", cbw->Flags); 97f16e43f8SFrank Wang debug("LUN %x\n", cbw->Lun); 98f16e43f8SFrank Wang debug("Length %x\n", cbw->Length); 99f16e43f8SFrank Wang debug("OptionCode %x\n", cbw->CDB[0]); 100f16e43f8SFrank Wang debug("SubCode %x\n", cbw->CDB[1]); 101f16e43f8SFrank Wang debug("SectorAddr %x\n", get_unaligned_be32(&cbw->CDB[2])); 102f16e43f8SFrank Wang debug("BlkSectors %x\n\n", get_unaligned_be16(&cbw->CDB[7])); 103f16e43f8SFrank Wang } 104f16e43f8SFrank Wang 105f16e43f8SFrank Wang static int rkusb_check_lun(struct fsg_common *common) 106f16e43f8SFrank Wang { 107f16e43f8SFrank Wang struct fsg_lun *curlun; 108f16e43f8SFrank Wang 109f16e43f8SFrank Wang /* Check the LUN */ 110f16e43f8SFrank Wang if (common->lun >= 0 && common->lun < common->nluns) { 111f16e43f8SFrank Wang curlun = &common->luns[common->lun]; 112f16e43f8SFrank Wang if (common->cmnd[0] != SC_REQUEST_SENSE) { 113f16e43f8SFrank Wang curlun->sense_data = SS_NO_SENSE; 114f16e43f8SFrank Wang curlun->info_valid = 0; 115f16e43f8SFrank Wang } 116f16e43f8SFrank Wang } else { 117f16e43f8SFrank Wang curlun = NULL; 118f16e43f8SFrank Wang common->bad_lun_okay = 0; 119f16e43f8SFrank Wang 120f16e43f8SFrank Wang /* 121f16e43f8SFrank Wang * INQUIRY and REQUEST SENSE commands are explicitly allowed 122f16e43f8SFrank Wang * to use unsupported LUNs; all others may not. 123f16e43f8SFrank Wang */ 124f16e43f8SFrank Wang if (common->cmnd[0] != SC_INQUIRY && 125f16e43f8SFrank Wang common->cmnd[0] != SC_REQUEST_SENSE) { 126f16e43f8SFrank Wang debug("unsupported LUN %d\n", common->lun); 127f16e43f8SFrank Wang return -EINVAL; 128f16e43f8SFrank Wang } 129f16e43f8SFrank Wang } 130f16e43f8SFrank Wang 131f16e43f8SFrank Wang return 0; 132f16e43f8SFrank Wang } 133f16e43f8SFrank Wang 134f16e43f8SFrank Wang static void __do_reset(struct usb_ep *ep, struct usb_request *req) 135f16e43f8SFrank Wang { 1365b081643SFrank Wang u32 boot_flag = BOOT_NORMAL; 1375b081643SFrank Wang 1385b081643SFrank Wang if (rkusb_rst_code == 0x03) 1395b081643SFrank Wang boot_flag = BOOT_BROM_DOWNLOAD; 1405b081643SFrank Wang 1415b081643SFrank Wang rkusb_rst_code = 0; /* restore to default */ 1425b081643SFrank Wang writel(boot_flag, (void *)CONFIG_ROCKCHIP_BOOT_MODE_REG); 143866d7966SJoseph Chen 144f16e43f8SFrank Wang do_reset(NULL, 0, 0, NULL); 145f16e43f8SFrank Wang } 146f16e43f8SFrank Wang 147f16e43f8SFrank Wang static int rkusb_do_reset(struct fsg_common *common, 148f16e43f8SFrank Wang struct fsg_buffhd *bh) 149f16e43f8SFrank Wang { 150f16e43f8SFrank Wang common->data_size_from_cmnd = common->cmnd[4]; 151f16e43f8SFrank Wang common->residue = 0; 152f16e43f8SFrank Wang bh->inreq->complete = __do_reset; 153f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 154f16e43f8SFrank Wang 1555b081643SFrank Wang rkusb_rst_code = !common->cmnd[1] ? 0xff : common->cmnd[1]; 156f16e43f8SFrank Wang return 0; 157f16e43f8SFrank Wang } 158f16e43f8SFrank Wang 159f16e43f8SFrank Wang static int rkusb_do_test_unit_ready(struct fsg_common *common, 160f16e43f8SFrank Wang struct fsg_buffhd *bh) 161f16e43f8SFrank Wang { 162f16e43f8SFrank Wang common->residue = 0x06 << 24; /* Max block xfer support from host */ 163f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 164f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 165f16e43f8SFrank Wang 166f16e43f8SFrank Wang return 0; 167f16e43f8SFrank Wang } 168f16e43f8SFrank Wang 169f16e43f8SFrank Wang static int rkusb_do_read_flash_id(struct fsg_common *common, 170f16e43f8SFrank Wang struct fsg_buffhd *bh) 171f16e43f8SFrank Wang { 172f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 173e0023032SKever Yang u32 len = 5; 174d7386f60SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 175f16e43f8SFrank Wang 176d7386f60SFrank Wang if (type == IF_TYPE_MMC) 177f16e43f8SFrank Wang memcpy((void *)&buf[0], "EMMC ", 5); 178d7386f60SFrank Wang else if (type == IF_TYPE_RKNAND) 179d7386f60SFrank Wang memcpy((void *)&buf[0], "NAND ", 5); 180d7386f60SFrank Wang else 181d7386f60SFrank Wang memcpy((void *)&buf[0], "UNKN ", 5); /* unknown */ 182f16e43f8SFrank Wang 183f16e43f8SFrank Wang /* Set data xfer size */ 184f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 185e0023032SKever Yang common->data_size = len; 186f16e43f8SFrank Wang 187f16e43f8SFrank Wang return len; 188f16e43f8SFrank Wang } 189f16e43f8SFrank Wang 190f16e43f8SFrank Wang static int rkusb_do_test_bad_block(struct fsg_common *common, 191f16e43f8SFrank Wang struct fsg_buffhd *bh) 192f16e43f8SFrank Wang { 193f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 194e0023032SKever Yang u32 len = 64; 195f16e43f8SFrank Wang 196f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 197f16e43f8SFrank Wang 198f16e43f8SFrank Wang /* Set data xfer size */ 199f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 200e0023032SKever Yang common->data_size = len; 201f16e43f8SFrank Wang 202f16e43f8SFrank Wang return len; 203f16e43f8SFrank Wang } 204f16e43f8SFrank Wang 205f16e43f8SFrank Wang static int rkusb_do_read_flash_info(struct fsg_common *common, 206f16e43f8SFrank Wang struct fsg_buffhd *bh) 207f16e43f8SFrank Wang { 208f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 209d23ec8c4SKever Yang u32 len = sizeof(struct rk_flash_info); 210f16e43f8SFrank Wang struct rk_flash_info finfo = { 211f16e43f8SFrank Wang .block_size = 1024, 212f16e43f8SFrank Wang .ecc_bits = 0, 213f16e43f8SFrank Wang .page_size = 4, 214f16e43f8SFrank Wang .access_time = 40, 215f16e43f8SFrank Wang .manufacturer = 0, 216f16e43f8SFrank Wang .flash_mask = 0 217f16e43f8SFrank Wang }; 218f16e43f8SFrank Wang 219f16e43f8SFrank Wang finfo.flash_size = (u32)ums[common->lun].block_dev.lba; 220f16e43f8SFrank Wang if (finfo.flash_size) 221f16e43f8SFrank Wang finfo.flash_mask = 1; 222f16e43f8SFrank Wang 223f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 224f16e43f8SFrank Wang memcpy((void *)&buf[0], (void *)&finfo, len); 225f16e43f8SFrank Wang 226f16e43f8SFrank Wang /* Set data xfer size */ 227f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 228d23ec8c4SKever Yang /* legacy upgrade_tool does not set correct transfer size */ 229d23ec8c4SKever Yang common->data_size = len; 230f16e43f8SFrank Wang 231f16e43f8SFrank Wang return len; 232f16e43f8SFrank Wang } 233f16e43f8SFrank Wang 234829f2b85SFrank Wang static int rkusb_do_get_chip_info(struct fsg_common *common, 235829f2b85SFrank Wang struct fsg_buffhd *bh) 236829f2b85SFrank Wang { 237829f2b85SFrank Wang u8 *buf = (u8 *)bh->buf; 238829f2b85SFrank Wang u32 len = common->data_size; 239829f2b85SFrank Wang u32 chip_info[4]; 240829f2b85SFrank Wang 241829f2b85SFrank Wang memset((void *)chip_info, 0, sizeof(chip_info)); 242829f2b85SFrank Wang rockchip_rockusb_get_chip_info(chip_info); 243829f2b85SFrank Wang 244829f2b85SFrank Wang memset((void *)&buf[0], 0, len); 245829f2b85SFrank Wang memcpy((void *)&buf[0], (void *)chip_info, len); 246829f2b85SFrank Wang 247829f2b85SFrank Wang /* Set data xfer size */ 248829f2b85SFrank Wang common->residue = common->data_size_from_cmnd = len; 249829f2b85SFrank Wang 250829f2b85SFrank Wang return len; 251829f2b85SFrank Wang } 252829f2b85SFrank Wang 253f16e43f8SFrank Wang static int rkusb_do_lba_erase(struct fsg_common *common, 254f16e43f8SFrank Wang struct fsg_buffhd *bh) 255f16e43f8SFrank Wang { 256f16e43f8SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 257f16e43f8SFrank Wang u32 lba, amount; 258f16e43f8SFrank Wang loff_t file_offset; 259f16e43f8SFrank Wang int rc; 260f16e43f8SFrank Wang 261f16e43f8SFrank Wang lba = get_unaligned_be32(&common->cmnd[2]); 262f16e43f8SFrank Wang if (lba >= curlun->num_sectors) { 263f16e43f8SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 264f16e43f8SFrank Wang rc = -EINVAL; 265f16e43f8SFrank Wang goto out; 266f16e43f8SFrank Wang } 267f16e43f8SFrank Wang 268f16e43f8SFrank Wang file_offset = ((loff_t) lba) << 9; 269f16e43f8SFrank Wang amount = get_unaligned_be16(&common->cmnd[7]) << 9; 270f16e43f8SFrank Wang if (unlikely(amount == 0)) { 271f16e43f8SFrank Wang curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 272f16e43f8SFrank Wang rc = -EIO; 273f16e43f8SFrank Wang goto out; 274f16e43f8SFrank Wang } 275f16e43f8SFrank Wang 276f16e43f8SFrank Wang /* Perform the erase */ 277f16e43f8SFrank Wang rc = ums[common->lun].erase_sector(&ums[common->lun], 278f16e43f8SFrank Wang file_offset / SECTOR_SIZE, 279f16e43f8SFrank Wang amount / SECTOR_SIZE); 280f16e43f8SFrank Wang if (!rc) { 281f16e43f8SFrank Wang curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 282f16e43f8SFrank Wang rc = -EIO; 283f16e43f8SFrank Wang } 284f16e43f8SFrank Wang 285f16e43f8SFrank Wang out: 286f16e43f8SFrank Wang common->data_dir = DATA_DIR_NONE; 287f16e43f8SFrank Wang bh->state = BUF_STATE_EMPTY; 288f16e43f8SFrank Wang 289f16e43f8SFrank Wang return rc; 290f16e43f8SFrank Wang } 291f16e43f8SFrank Wang 2920d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 2930d0c3248SFrank Wang static int rkusb_do_vs_write(struct fsg_common *common) 2940d0c3248SFrank Wang { 2950d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 2960d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 2970d0c3248SFrank Wang struct vendor_item *vhead; 2980d0c3248SFrank Wang struct fsg_buffhd *bh; 2990d0c3248SFrank Wang void *data; 3000d0c3248SFrank Wang int rc; 3010d0c3248SFrank Wang 3020d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 3030d0c3248SFrank Wang /* _MUST_ small than 64K */ 3040d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 3050d0c3248SFrank Wang return -EINVAL; 3060d0c3248SFrank Wang } 3070d0c3248SFrank Wang 3080d0c3248SFrank Wang common->residue = common->data_size; 3090d0c3248SFrank Wang common->usb_amount_left = common->data_size; 3100d0c3248SFrank Wang 3110d0c3248SFrank Wang /* Carry out the file writes */ 3120d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 3130d0c3248SFrank Wang return -EIO; /* No data to write */ 3140d0c3248SFrank Wang 3150d0c3248SFrank Wang for (;;) { 3160d0c3248SFrank Wang if (common->usb_amount_left > 0) { 3170d0c3248SFrank Wang /* Wait for the next buffer to become available */ 3180d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 3190d0c3248SFrank Wang if (bh->state != BUF_STATE_EMPTY) 3200d0c3248SFrank Wang goto wait; 3210d0c3248SFrank Wang 3220d0c3248SFrank Wang /* Request the next buffer */ 3230d0c3248SFrank Wang common->usb_amount_left -= common->data_size; 3240d0c3248SFrank Wang bh->outreq->length = common->data_size; 3250d0c3248SFrank Wang bh->bulk_out_intended_length = common->data_size; 3260d0c3248SFrank Wang bh->outreq->short_not_ok = 1; 3270d0c3248SFrank Wang 3280d0c3248SFrank Wang START_TRANSFER_OR(common, bulk_out, bh->outreq, 3290d0c3248SFrank Wang &bh->outreq_busy, &bh->state) 3300d0c3248SFrank Wang /* 3310d0c3248SFrank Wang * Don't know what to do if 3320d0c3248SFrank Wang * common->fsg is NULL 3330d0c3248SFrank Wang */ 3340d0c3248SFrank Wang return -EIO; 3350d0c3248SFrank Wang common->next_buffhd_to_fill = bh->next; 3360d0c3248SFrank Wang } else { 3370d0c3248SFrank Wang /* Then, wait for the data to become available */ 3380d0c3248SFrank Wang bh = common->next_buffhd_to_drain; 3390d0c3248SFrank Wang if (bh->state != BUF_STATE_FULL) 3400d0c3248SFrank Wang goto wait; 3410d0c3248SFrank Wang 3420d0c3248SFrank Wang common->next_buffhd_to_drain = bh->next; 3430d0c3248SFrank Wang bh->state = BUF_STATE_EMPTY; 3440d0c3248SFrank Wang 3450d0c3248SFrank Wang /* Did something go wrong with the transfer? */ 3460d0c3248SFrank Wang if (bh->outreq->status != 0) { 3470d0c3248SFrank Wang curlun->sense_data = SS_COMMUNICATION_FAILURE; 3480d0c3248SFrank Wang curlun->info_valid = 1; 3490d0c3248SFrank Wang break; 3500d0c3248SFrank Wang } 3510d0c3248SFrank Wang 3520d0c3248SFrank Wang /* Perform the write */ 3530d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 3540d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 3550d0c3248SFrank Wang 3560d0c3248SFrank Wang if (!type) { 3570d0c3248SFrank Wang /* Vendor storage */ 3580d0c3248SFrank Wang rc = vendor_storage_write(vhead->id, 3590d0c3248SFrank Wang (char __user *)data, 3600d0c3248SFrank Wang vhead->size); 361*19652be0SFrank Wang if (rc < 0) { 362*19652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 3630d0c3248SFrank Wang return -EIO; 364*19652be0SFrank Wang } 3650d0c3248SFrank Wang } else { 3660d0c3248SFrank Wang /* RPMB */ 3676f0347c8Stony.xu rc = 3686f0347c8Stony.xu write_keybox_to_secure_storage((u8 *)data, 3696f0347c8Stony.xu vhead->size); 370*19652be0SFrank Wang if (rc < 0) { 371*19652be0SFrank Wang curlun->sense_data = SS_WRITE_ERROR; 3726f0347c8Stony.xu return -EIO; 3730d0c3248SFrank Wang } 374*19652be0SFrank Wang } 3750d0c3248SFrank Wang 3760d0c3248SFrank Wang common->residue -= common->data_size; 3770d0c3248SFrank Wang 3780d0c3248SFrank Wang /* Did the host decide to stop early? */ 3790d0c3248SFrank Wang if (bh->outreq->actual != bh->outreq->length) 3800d0c3248SFrank Wang common->short_packet_received = 1; 3810d0c3248SFrank Wang break; /* Command done */ 3820d0c3248SFrank Wang } 3830d0c3248SFrank Wang wait: 3840d0c3248SFrank Wang /* Wait for something to happen */ 3850d0c3248SFrank Wang rc = sleep_thread(common); 3860d0c3248SFrank Wang if (rc) 3870d0c3248SFrank Wang return rc; 3880d0c3248SFrank Wang } 3890d0c3248SFrank Wang 3900d0c3248SFrank Wang return -EIO; /* No default reply */ 3910d0c3248SFrank Wang } 3920d0c3248SFrank Wang 3930d0c3248SFrank Wang static int rkusb_do_vs_read(struct fsg_common *common) 3940d0c3248SFrank Wang { 3950d0c3248SFrank Wang struct fsg_lun *curlun = &common->luns[common->lun]; 3960d0c3248SFrank Wang u16 type = get_unaligned_be16(&common->cmnd[4]); 3970d0c3248SFrank Wang struct vendor_item *vhead; 3980d0c3248SFrank Wang struct fsg_buffhd *bh; 3990d0c3248SFrank Wang void *data; 4000d0c3248SFrank Wang int rc; 4010d0c3248SFrank Wang 4020d0c3248SFrank Wang if (common->data_size >= (u32)65536) { 4030d0c3248SFrank Wang /* _MUST_ small than 64K */ 4040d0c3248SFrank Wang curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 4050d0c3248SFrank Wang return -EINVAL; 4060d0c3248SFrank Wang } 4070d0c3248SFrank Wang 4080d0c3248SFrank Wang common->residue = common->data_size; 4090d0c3248SFrank Wang common->usb_amount_left = common->data_size; 4100d0c3248SFrank Wang 4110d0c3248SFrank Wang /* Carry out the file reads */ 4120d0c3248SFrank Wang if (unlikely(common->data_size == 0)) 4130d0c3248SFrank Wang return -EIO; /* No default reply */ 4140d0c3248SFrank Wang 4150d0c3248SFrank Wang for (;;) { 4160d0c3248SFrank Wang /* Wait for the next buffer to become available */ 4170d0c3248SFrank Wang bh = common->next_buffhd_to_fill; 4180d0c3248SFrank Wang while (bh->state != BUF_STATE_EMPTY) { 4190d0c3248SFrank Wang rc = sleep_thread(common); 4200d0c3248SFrank Wang if (rc) 4210d0c3248SFrank Wang return rc; 4220d0c3248SFrank Wang } 4230d0c3248SFrank Wang 4240d0c3248SFrank Wang memset(bh->buf, 0, FSG_BUFLEN); 4250d0c3248SFrank Wang vhead = (struct vendor_item *)bh->buf; 4260d0c3248SFrank Wang data = bh->buf + sizeof(struct vendor_item); 4270d0c3248SFrank Wang vhead->id = get_unaligned_be16(&common->cmnd[2]); 4280d0c3248SFrank Wang 4290d0c3248SFrank Wang if (!type) { 4300d0c3248SFrank Wang /* Vendor storage */ 4310d0c3248SFrank Wang rc = vendor_storage_read(vhead->id, 4320d0c3248SFrank Wang (char __user *)data, 4330d0c3248SFrank Wang common->data_size); 434*19652be0SFrank Wang if (!rc) { 435*19652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 4360d0c3248SFrank Wang return -EIO; 437*19652be0SFrank Wang } 4380d0c3248SFrank Wang vhead->size = rc; 4390d0c3248SFrank Wang } else { 4400d0c3248SFrank Wang /* RPMB */ 441700a3668STony Xu rc = 442700a3668STony Xu read_raw_data_from_secure_storage((u8 *)data, 443700a3668STony Xu common->data_size); 444*19652be0SFrank Wang if (!rc) { 445*19652be0SFrank Wang curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 446700a3668STony Xu return -EIO; 447*19652be0SFrank Wang } 448700a3668STony Xu vhead->size = rc; 4490d0c3248SFrank Wang } 4500d0c3248SFrank Wang 4510d0c3248SFrank Wang common->residue -= common->data_size; 4520d0c3248SFrank Wang bh->inreq->length = common->data_size; 4530d0c3248SFrank Wang bh->state = BUF_STATE_FULL; 4540d0c3248SFrank Wang 4550d0c3248SFrank Wang break; /* No more left to read */ 4560d0c3248SFrank Wang } 4570d0c3248SFrank Wang 4580d0c3248SFrank Wang return -EIO; /* No default reply */ 4590d0c3248SFrank Wang } 4600d0c3248SFrank Wang #endif 4610d0c3248SFrank Wang 462f16e43f8SFrank Wang static int rkusb_do_read_capacity(struct fsg_common *common, 463f16e43f8SFrank Wang struct fsg_buffhd *bh) 464f16e43f8SFrank Wang { 465f16e43f8SFrank Wang u8 *buf = (u8 *)bh->buf; 466f16e43f8SFrank Wang u32 len = common->data_size; 467d015bf41SFrank Wang enum if_type type = ums[common->lun].block_dev.if_type; 468f16e43f8SFrank Wang 469f16e43f8SFrank Wang /* 470f16e43f8SFrank Wang * bit[0]: Direct LBA, 0: Disabled; 4710d0c3248SFrank Wang * bit[1]: Vendor Storage API, 0: Disabed (default); 472d015bf41SFrank Wang * bit[2]: First 4M Access, 0: Disabled; 4730d0c3248SFrank Wang * bit[3]: Read LBA On, 0: Disabed (default); 4740d0c3248SFrank Wang * bit[4]: New Vendor Storage API, 0: Disabed; 4750d0c3248SFrank Wang * bit[5:63}: Reserved. 476f16e43f8SFrank Wang */ 477f16e43f8SFrank Wang memset((void *)&buf[0], 0, len); 478af5a2012SJason Zhu if (type == IF_TYPE_MMC || type == IF_TYPE_SD) 4790d0c3248SFrank Wang buf[0] = BIT(0) | BIT(2) | BIT(4); 4800d0c3248SFrank Wang else 4810d0c3248SFrank Wang buf[0] = BIT(0) | BIT(4); 482f16e43f8SFrank Wang 483f16e43f8SFrank Wang /* Set data xfer size */ 484f16e43f8SFrank Wang common->residue = common->data_size_from_cmnd = len; 485f16e43f8SFrank Wang 486f16e43f8SFrank Wang return len; 487f16e43f8SFrank Wang } 488f16e43f8SFrank Wang 489d23ec8c4SKever Yang static void rkusb_fixup_cbwcb(struct fsg_common *common, 490d23ec8c4SKever Yang struct fsg_buffhd *bh) 491d23ec8c4SKever Yang { 492d23ec8c4SKever Yang struct usb_request *req = bh->outreq; 493d23ec8c4SKever Yang struct fsg_bulk_cb_wrap *cbw = req->buf; 494d23ec8c4SKever Yang 495d23ec8c4SKever Yang /* FIXME cbw.DataTransferLength was not set by Upgrade Tool */ 496d23ec8c4SKever Yang common->data_size = le32_to_cpu(cbw->DataTransferLength); 497d23ec8c4SKever Yang if (common->data_size == 0) { 498d23ec8c4SKever Yang common->data_size = 499d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]) << 9; 500d23ec8c4SKever Yang printf("Trasfer Length NOT set, please use new version tool\n"); 501d23ec8c4SKever Yang debug("%s %d, cmnd1 %x\n", __func__, 502d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[7]), 503d23ec8c4SKever Yang get_unaligned_be16(&common->cmnd[1])); 504d23ec8c4SKever Yang } 505d23ec8c4SKever Yang if (cbw->Flags & USB_BULK_IN_FLAG) 506d23ec8c4SKever Yang common->data_dir = DATA_DIR_TO_HOST; 507d23ec8c4SKever Yang else 508d23ec8c4SKever Yang common->data_dir = DATA_DIR_FROM_HOST; 509d23ec8c4SKever Yang 510d23ec8c4SKever Yang /* Not support */ 511d23ec8c4SKever Yang common->cmnd[1] = 0; 512d23ec8c4SKever Yang } 513d23ec8c4SKever Yang 514f16e43f8SFrank Wang static int rkusb_cmd_process(struct fsg_common *common, 515f16e43f8SFrank Wang struct fsg_buffhd *bh, int *reply) 516f16e43f8SFrank Wang { 517f16e43f8SFrank Wang struct usb_request *req = bh->outreq; 518f16e43f8SFrank Wang struct fsg_bulk_cb_wrap *cbw = req->buf; 519f16e43f8SFrank Wang int rc; 520f16e43f8SFrank Wang 521f16e43f8SFrank Wang dump_cbw(cbw); 522f16e43f8SFrank Wang 523f16e43f8SFrank Wang if (rkusb_check_lun(common)) { 524f16e43f8SFrank Wang *reply = -EINVAL; 525f16e43f8SFrank Wang return RKUSB_RC_ERROR; 526f16e43f8SFrank Wang } 527f16e43f8SFrank Wang 528f16e43f8SFrank Wang switch (common->cmnd[0]) { 529f16e43f8SFrank Wang case RKUSB_TEST_UNIT_READY: 530f16e43f8SFrank Wang *reply = rkusb_do_test_unit_ready(common, bh); 531f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 532f16e43f8SFrank Wang break; 533f16e43f8SFrank Wang 534f16e43f8SFrank Wang case RKUSB_READ_FLASH_ID: 535f16e43f8SFrank Wang *reply = rkusb_do_read_flash_id(common, bh); 536f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 537f16e43f8SFrank Wang break; 538f16e43f8SFrank Wang 539f16e43f8SFrank Wang case RKUSB_TEST_BAD_BLOCK: 540f16e43f8SFrank Wang *reply = rkusb_do_test_bad_block(common, bh); 541f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 542f16e43f8SFrank Wang break; 543f16e43f8SFrank Wang 544f16e43f8SFrank Wang case RKUSB_LBA_READ_10: 5455fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 546f16e43f8SFrank Wang common->cmnd[0] = SC_READ_10; 547f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 548f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 549f16e43f8SFrank Wang break; 550f16e43f8SFrank Wang 551f16e43f8SFrank Wang case RKUSB_LBA_WRITE_10: 5525fb597c2SKever Yang rkusb_fixup_cbwcb(common, bh); 553f16e43f8SFrank Wang common->cmnd[0] = SC_WRITE_10; 554f16e43f8SFrank Wang common->cmnd[1] = 0; /* Not support */ 555f16e43f8SFrank Wang rc = RKUSB_RC_CONTINUE; 556f16e43f8SFrank Wang break; 557f16e43f8SFrank Wang 558f16e43f8SFrank Wang case RKUSB_READ_FLASH_INFO: 559f16e43f8SFrank Wang *reply = rkusb_do_read_flash_info(common, bh); 560f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 561f16e43f8SFrank Wang break; 562f16e43f8SFrank Wang 563829f2b85SFrank Wang case RKUSB_GET_CHIP_VER: 564829f2b85SFrank Wang *reply = rkusb_do_get_chip_info(common, bh); 565829f2b85SFrank Wang rc = RKUSB_RC_FINISHED; 566829f2b85SFrank Wang break; 567829f2b85SFrank Wang 568f16e43f8SFrank Wang case RKUSB_LBA_ERASE: 569f16e43f8SFrank Wang *reply = rkusb_do_lba_erase(common, bh); 570f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 571f16e43f8SFrank Wang break; 572f16e43f8SFrank Wang 5730d0c3248SFrank Wang #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION 5740d0c3248SFrank Wang case RKUSB_VS_WRITE: 5750d0c3248SFrank Wang *reply = rkusb_do_vs_write(common); 5760d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 5770d0c3248SFrank Wang break; 5780d0c3248SFrank Wang 5790d0c3248SFrank Wang case RKUSB_VS_READ: 5800d0c3248SFrank Wang *reply = rkusb_do_vs_read(common); 5810d0c3248SFrank Wang rc = RKUSB_RC_FINISHED; 5820d0c3248SFrank Wang break; 5830d0c3248SFrank Wang #endif 5840d0c3248SFrank Wang 585f16e43f8SFrank Wang case RKUSB_READ_CAPACITY: 586f16e43f8SFrank Wang *reply = rkusb_do_read_capacity(common, bh); 587f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 588f16e43f8SFrank Wang break; 589f16e43f8SFrank Wang 590f16e43f8SFrank Wang case RKUSB_RESET: 591f16e43f8SFrank Wang *reply = rkusb_do_reset(common, bh); 592f16e43f8SFrank Wang rc = RKUSB_RC_FINISHED; 593f16e43f8SFrank Wang break; 594f16e43f8SFrank Wang 595f16e43f8SFrank Wang case RKUSB_READ_10: 596f16e43f8SFrank Wang case RKUSB_WRITE_10: 597e0023032SKever Yang printf("CMD Not support, pls use new version Tool\n"); 598e0023032SKever Yang case RKUSB_SET_DEVICE_ID: 599f16e43f8SFrank Wang case RKUSB_ERASE_10: 600f16e43f8SFrank Wang case RKUSB_WRITE_SPARE: 601f16e43f8SFrank Wang case RKUSB_READ_SPARE: 602f16e43f8SFrank Wang case RKUSB_ERASE_10_FORCE: 603f16e43f8SFrank Wang case RKUSB_GET_VERSION: 604f16e43f8SFrank Wang case RKUSB_ERASE_SYS_DISK: 605f16e43f8SFrank Wang case RKUSB_SDRAM_READ_10: 606f16e43f8SFrank Wang case RKUSB_SDRAM_WRITE_10: 607f16e43f8SFrank Wang case RKUSB_SDRAM_EXECUTE: 608f16e43f8SFrank Wang case RKUSB_LOW_FORMAT: 609f16e43f8SFrank Wang case RKUSB_SET_RESET_FLAG: 610f16e43f8SFrank Wang case RKUSB_SPI_READ_10: 611f16e43f8SFrank Wang case RKUSB_SPI_WRITE_10: 612f16e43f8SFrank Wang case RKUSB_SESSION: 613f16e43f8SFrank Wang /* Fall through */ 614f16e43f8SFrank Wang default: 615f16e43f8SFrank Wang rc = RKUSB_RC_UNKNOWN_CMND; 616f16e43f8SFrank Wang break; 617f16e43f8SFrank Wang } 618f16e43f8SFrank Wang 619f16e43f8SFrank Wang return rc; 620f16e43f8SFrank Wang } 621f16e43f8SFrank Wang 622f16e43f8SFrank Wang DECLARE_GADGET_BIND_CALLBACK(rkusb_ums_dnl, fsg_add); 623