[U-Boot] [U-Boot 0/3] introduce Rockchip rockusb

rockusb is a protocol run between host pc and device. it help people get device info, flash image to device. this patch implement rockusb on device side.
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++++++++++++ include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h

this patch implement fastboot protocol on the device side. this is based on USB download gadget infrastructure. the rockusb function implements the rd, wl, rid commands. it can work with rkdeveloptool; https://github.com/rockchip-linux/rkdeveloptool
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com --- drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 802 insertions(+) create mode 100644 drivers/usb/gadget/f_rockusb.c
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 0fbbb7c..0eb27a3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c new file mode 100644 index 0000000..a67cb35 --- /dev/null +++ b/drivers/usb/gadget/f_rockusb.c @@ -0,0 +1,801 @@ +/* + * (C) Copyright 2017 + * + * Eddie Cai eddie.cai.linux@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> +#include <linux/compiler.h> +#include <version.h> +#include <g_dnl.h> + +#define ROCKUSB_VERSION "0.1" + +#define ROCKUSB_INTERFACE_CLASS 0xff +#define ROCKUSB_INTERFACE_SUB_CLASS 0x06 +#define ROCKUSB_INTERFACE_PROTOCOL 0x05 + +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200) +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040) +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040) + +#define EP_BUFFER_SIZE 4096 +/* + * EP_BUFFER_SIZE must always be an integral multiple of maxpacket size + * (64 or 512 or 1024), else we break on certain controllers like DWC3 + * that expect bulk OUT requests to be divisible by maxpacket size. + */ + +struct f_rockusb { + struct usb_function usb_function; + + /* IN/OUT EP's and corresponding requests */ + struct usb_ep *in_ep, *out_ep; + struct usb_request *in_req, *out_req; +}; + +static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) +{ + return container_of(f, struct f_rockusb, usb_function); +} + +static struct f_rockusb *rockusb_func; + +static struct usb_endpoint_descriptor fs_ep_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), +}; + +static struct usb_endpoint_descriptor fs_ep_out = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), +}; + +static struct usb_endpoint_descriptor hs_ep_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor hs_ep_out = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_interface_descriptor interface_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = ROCKUSB_INTERFACE_CLASS, + .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS, + .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL, +}; + +static struct usb_descriptor_header *rkusb_fs_function[] = { + (struct usb_descriptor_header *)&interface_desc, + (struct usb_descriptor_header *)&fs_ep_in, + (struct usb_descriptor_header *)&fs_ep_out, +}; + +static struct usb_descriptor_header *rkusb_hs_function[] = { + (struct usb_descriptor_header *)&interface_desc, + (struct usb_descriptor_header *)&hs_ep_in, + (struct usb_descriptor_header *)&hs_ep_out, + NULL, +}; + +static struct usb_endpoint_descriptor * +rkusb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, + struct usb_endpoint_descriptor *hs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + +/* + * static strings, in UTF-8 + */ +static const char rkusb_name[] = "Rockchip Rockusb"; + +static struct usb_string rkusb_string_defs[] = { + [0].s = rkusb_name, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_rkusb = { + .language = 0x0409, /* en-us */ + .strings = rkusb_string_defs, +}; + +static struct usb_gadget_strings *rkusb_strings[] = { + &stringtab_rkusb, + NULL, +}; + +static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); +static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size); + +static void rockusb_complete(struct usb_ep *ep, struct usb_request *req) +{ + int status = req->status; + if (!status) + return; + debug("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual); +} + +static int rockusb_bind(struct usb_configuration *c, struct usb_function *f) +{ + int id; + struct usb_gadget *gadget = c->cdev->gadget; + struct f_rockusb *f_rkusb = func_to_rockusb(f); + const char *s; + + id = usb_interface_id(c, f); + if (id < 0) + return id; + interface_desc.bInterfaceNumber = id; + + id = usb_string_id(c->cdev); + if (id < 0) + return id; + + rkusb_string_defs[0].id = id; + interface_desc.iInterface = id; + + f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in); + if (!f_rkusb->in_ep) + return -ENODEV; + f_rkusb->in_ep->driver_data = c->cdev; + + f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out); + if (!f_rkusb->out_ep) + return -ENODEV; + f_rkusb->out_ep->driver_data = c->cdev; + + f->descriptors = rkusb_fs_function; + + if (gadget_is_dualspeed(gadget)) { + hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress; + hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress; + f->hs_descriptors = rkusb_hs_function; + } + + s = getenv("serial#"); + if (s) + g_dnl_set_serialnumber((char *)s); + + return 0; +} + +static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f) +{ + memset(rockusb_func, 0, sizeof(*rockusb_func)); +} + +static void rockusb_disable(struct usb_function *f) +{ + struct f_rockusb *f_rkusb = func_to_rockusb(f); + + usb_ep_disable(f_rkusb->out_ep); + usb_ep_disable(f_rkusb->in_ep); + + if (f_rkusb->out_req) { + free(f_rkusb->out_req->buf); + usb_ep_free_request(f_rkusb->out_ep, f_rkusb->out_req); + f_rkusb->out_req = NULL; + } + if (f_rkusb->in_req) { + free(f_rkusb->in_req->buf); + usb_ep_free_request(f_rkusb->in_ep, f_rkusb->in_req); + f_rkusb->in_req = NULL; + } +} + +static struct usb_request *rockusb_start_ep(struct usb_ep *ep) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, 0); + if (!req) + return NULL; + + req->length = EP_BUFFER_SIZE; + req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE); + if (!req->buf) { + usb_ep_free_request(ep, req); + return NULL; + } + + memset(req->buf, 0, req->length); + return req; +} + +static int rockusb_set_alt(struct usb_function *f, + unsigned interface, unsigned alt) +{ + int ret; + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_gadget *gadget = cdev->gadget; + struct f_rockusb *f_rkusb = func_to_rockusb(f); + const struct usb_endpoint_descriptor *d; + + debug("%s: func: %s intf: %d alt: %d\n", + __func__, f->name, interface, alt); + + d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out); + ret = usb_ep_enable(f_rkusb->out_ep, d); + if (ret) { + puts("failed to enable out ep\n"); + return ret; + } + + f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep); + if (!f_rkusb->out_req) { + puts("failed to alloc out req\n"); + ret = -EINVAL; + goto err; + } + f_rkusb->out_req->complete = rx_handler_command; + + d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in); + ret = usb_ep_enable(f_rkusb->in_ep, d); + if (ret) { + puts("failed to enable in ep\n"); + goto err; + } + + f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep); + if (!f_rkusb->in_req) { + puts("failed alloc req in\n"); + ret = -EINVAL; + goto err; + } + f_rkusb->in_req->complete = rockusb_complete; + + ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0); + if (ret) + goto err; + + return 0; +err: + rockusb_disable(f); + return ret; +} + +static int rockusb_add(struct usb_configuration *c) +{ + struct f_rockusb *f_rkusb = rockusb_func; + int status; + + debug("%s: cdev: 0x%p\n", __func__, c->cdev); + + if (!f_rkusb) { + f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_rkusb)); + if (!f_rkusb) + return -ENOMEM; + + rockusb_func = f_rkusb; + memset(f_rkusb, 0, sizeof(*f_rkusb)); + } + + f_rkusb->usb_function.name = "f_rockusb"; + f_rkusb->usb_function.bind = rockusb_bind; + f_rkusb->usb_function.unbind = rockusb_unbind; + f_rkusb->usb_function.set_alt = rockusb_set_alt; + f_rkusb->usb_function.disable = rockusb_disable; + f_rkusb->usb_function.strings = rkusb_strings; + + status = usb_add_function(c, &f_rkusb->usb_function); + if (status) { + free(f_rkusb); + rockusb_func = f_rkusb; + } + return status; +} + +char *rockusb_dev_type = 0; +int rockusb_dev_index = 0; + +void rockusb_dev_init(char *dev_type, int dev_index) +{ + rockusb_dev_type = dev_type; + rockusb_dev_index = dev_index; +} + +DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add); + +static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) +{ + struct usb_request *in_req = rockusb_func->in_req; + int ret; + + memcpy(in_req->buf, buffer, buffer_size); + in_req->length = buffer_size; + usb_ep_dequeue(rockusb_func->in_ep, in_req); + ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0); + if (ret) + printf("Error %d on queue\n", ret); + return 0; +} + +static int rockusb_tx_write_str(const char *buffer) +{ + return rockusb_tx_write(buffer, strlen(buffer)); +} + +/* Bulk-only data structures */ + +/* Command Block Wrapper */ +struct fsg_bulk_cb_wrap { + __le32 Signature; /* Contains 'USBC' */ + u32 Tag; /* Unique per command id */ + __le32 DataTransferLength; /* Size of the data */ + u8 Flags; /* Direction in bit 7 */ + u8 Lun; /* LUN (normally 0) */ + u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */ + u8 CDB[16]; /* Command Data Block */ +}; + +#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80 + +/* Command Status Wrapper */ +struct bulk_cs_wrap { + __le32 Signature; /* Should = 'USBS' */ + u32 Tag; /* Same as original command */ + __le32 Residue; /* Amount not transferred */ + u8 Status; /* See below */ +}; + +#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2 + + +#define CSW_GOOD 0x00 +#define CSW_FAIL 0x01 + +static void printcbw(char *buf) +{ + struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN))); + + memcpy((char*)&cbw, buf, USB_BULK_CB_WRAP_LEN); + + debug("cbw: Signature:%x\n", cbw.Signature); + debug("cbw: Tag=%x\n", cbw.Tag); + debug("cbw: DataTransferLength=%d\n", cbw.DataTransferLength); + debug("cbw: Flags=%x\n", cbw.Flags); + debug("cbw: Lun=%d\n", cbw.Lun); + debug("cbw: Length=%d\n", cbw.Length); + debug("cbw: ucOperCode=%x\n", cbw.CDB[0]); + debug("cbw: ucReserved=%x\n", cbw.CDB[1]); + debug("cbw: dwAddress:%x %x %x %x\n", cbw.CDB[5], cbw.CDB[4], + cbw.CDB[3], cbw.CDB[2]); + debug("cbw: ucReserved2=%x\n", cbw.CDB[6]); + debug("cbw: usLength:%x %x\n", cbw.CDB[8], cbw.CDB[7]); + +} + +static void printcsw(char *buf) +{ + struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DMA_MINALIGN))); + + memcpy((char*)&csw, buf, USB_BULK_CS_WRAP_LEN); + debug("csw: Signature:%x\n", csw.Signature); + debug("csw: Tag:%x\n", csw.Tag); + debug("csw: Residue:%x\n", csw.Residue); + debug("csw: Status:%x\n", csw.Status); + +} + +static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size) +{ + struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DMA_MINALIGN))); + csw.Signature = cpu_to_le32(USB_BULK_CS_SIG); + csw.Tag = Tag; + csw.Residue = cpu_to_be32(residue); + csw.Status = Status; + printcsw((char*)&csw); + return rockusb_tx_write((char*)&csw, size); +} + +int download_tag = 0; +int download_lba = 0; +static unsigned int download_size; +static unsigned int download_bytes; +struct blk_desc *download_desc = 0; + +static unsigned int rx_bytes_expected(struct usb_ep *ep) +{ + int rx_remain = download_size - download_bytes; + unsigned int rem; + unsigned int maxpacket = ep->maxpacket; + + if (rx_remain <= 0) + return 0; + else if (rx_remain > EP_BUFFER_SIZE) + return EP_BUFFER_SIZE; + + rem = rx_remain % maxpacket; + if (rem > 0) + rx_remain = rx_remain + (maxpacket - rem); + + return rx_remain; +} + +static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) +{ + unsigned int transfer_size = download_size - download_bytes; + const unsigned char *buffer = req->buf; + unsigned int buffer_size = req->actual; + + if(!download_desc){ + printf("rx_handler_dl_image blk_get_dev\n"); + download_desc = blk_get_dev(rockusb_dev_type, rockusb_dev_index); + if (!download_desc || download_desc->type == DEV_TYPE_UNKNOWN){ + error("invalid mmc device\n"); + rockusb_tx_write_csw(download_tag, 0, CSW_FAIL, + USB_BULK_CS_WRAP_LEN); + return; + } + } + + if (req->status != 0) { + printf("Bad status: %d\n", req->status); + rockusb_tx_write_csw(download_tag, 0, + CSW_FAIL, USB_BULK_CS_WRAP_LEN); + return; + } + + if (buffer_size < transfer_size) + transfer_size = buffer_size; + + memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes, + buffer, transfer_size); + download_bytes += transfer_size; + + /* Check if transfer is done */ + if (download_bytes >= download_size) { + int blks = 0, blkcnt = download_size/512; + printf("download %d bytes finished, start writing to lba %x\n", + download_bytes, download_lba); + blks = blk_dwrite(download_desc, download_lba, blkcnt, + (char*)CONFIG_FASTBOOT_BUF_ADDR); + if (blks != blkcnt) { + error("failed writing to device %s: %d\n", + rockusb_dev_type, rockusb_dev_index); + rockusb_tx_write_csw(download_tag, 0, + CSW_FAIL, USB_BULK_CS_WRAP_LEN); + return; + } + + req->complete = rx_handler_command; + req->length = EP_BUFFER_SIZE; + download_size = 0; + printf("done\n"); + rockusb_tx_write_csw(download_tag, 0, CSW_GOOD, + USB_BULK_CS_WRAP_LEN); + } else { + req->length = rx_bytes_expected(ep); + } + + req->actual = 0; + usb_ep_queue(ep, req, 0); +} + +static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN))); + + memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN); + + rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, + CSW_GOOD, USB_BULK_CS_WRAP_LEN); + +} + +static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN))); + char emmc_id[] = "EMMC "; + + printf("cb_read_storage_id\n"); + memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN); + rockusb_tx_write_str(emmc_id);//only support emmc now + rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, CSW_GOOD, + USB_BULK_CS_WRAP_LEN); +} + +static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN))); + int sector_count; + + memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN); + sector_count = (int)get_unaligned_be16(&cbw.CDB[7]); + download_lba = get_unaligned_be32(&cbw.CDB[2]); + download_size = sector_count * 512; + download_bytes = 0; + download_tag = cbw.Tag; + if ((0 == download_size) || (download_size>CONFIG_FASTBOOT_BUF_SIZE)){ + rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, + CSW_FAIL, USB_BULK_CS_WRAP_LEN); + } else { + req->complete = rx_handler_dl_image; + req->length = rx_bytes_expected(ep); + } +} + +static int reboot_flag; + +int __weak rkusb_set_reboot_flag(int flag) +{ + printf("rkusb_set_reboot_flag: %d\n", reboot_flag); + return -ENOSYS; +} + +static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) +{ + rkusb_set_reboot_flag(reboot_flag); + do_reset(NULL, 0, 0, NULL); +} + +static void cb_reboot(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN))); + reboot_flag = 0; + memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN); + reboot_flag = cbw.CDB[1]; + rockusb_func->in_req->complete = compl_do_reset; + rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, CSW_GOOD, + USB_BULK_CS_WRAP_LEN); +} + +static void cb_not_support(struct usb_ep *ep, struct usb_request *req) +{ + struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN))); + + memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN); + printf("Rockusb command %x not support yet\n", cbw.CDB[0]); + rockusb_tx_write_csw(cbw.Tag, 0, CSW_FAIL, USB_BULK_CS_WRAP_LEN); +} + +#define RKUSB_STATUS_IDLE 0 +#define RKUSB_STATUS_CMD 1 +#define RKUSB_STATUS_RXDATA 2 +#define RKUSB_STATUS_TXDATA 3 +#define RKUSB_STATUS_CSW 4 +#define RKUSB_STATUS_RXDATA_PREPARE 5 +#define RKUSB_STATUS_TXDATA_PREPARE 6 + +typedef enum { + TEST_UNIT_READY = 0, + READ_FLASH_ID = 0x01, + TEST_BAD_BLOCK = 0x03, + READ_SECTOR = 0x04, + WRITE_SECTOR = 0x05, + ERASE_NORMAL = 0x06, + ERASE_FORCE = 0x0B, + READ_LBA = 0x14, + WRITE_LBA = 0x15, + ERASE_SYSTEMDISK = 0x16, + READ_SDRAM = 0x17, + WRITE_SDRAM = 0x18, + EXECUTE_SDRAM = 0x19, + READ_FLASH_INFO = 0x1A, + READ_CHIP_INFO = 0x1B, + SET_RESET_FLAG = 0x1E, + WRITE_EFUSE = 0x1F, + READ_EFUSE = 0x20, + READ_SPI_FLASH = 0x21, + WRITE_SPI_FLASH = 0x22, + WRITE_NEW_EFUSE = 0x23, + READ_NEW_EFUSE = 0x24, + DEVICE_RESET = 0xFF +} USB_OPERATION_CODE; + +#define K_FW_TEST_UNIT_READY 0x00 +#define K_FW_READ_FLASH_ID 0x01 +#define K_FW_SET_DEVICE_ID 0x02 +#define K_FW_TEST_BAD_BLOCK 0x03 +#define K_FW_READ_10 0x04 +#define K_FW_WRITE_10 0x05 +#define K_FW_ERASE_10 0x06 +#define K_FW_WRITE_SPARE 0x07 +#define K_FW_READ_SPARE 0x08 + +#define K_FW_ERASE_10_FORCE 0x0b +#define K_FW_GET_VERSION 0x0c + +#define K_FW_LBA_READ_10 0x14 +#define K_FW_LBA_WRITE_10 0x15 +#define K_FW_ERASE_SYS_DISK 0x16 +#define K_FW_SDRAM_READ_10 0x17 +#define K_FW_SDRAM_WRITE_10 0x18 +#define K_FW_SDRAM_EXECUTE 0x19 +#define K_FW_READ_FLASH_INFO 0x1A +#define K_FW_GET_CHIP_VER 0x1B +#define K_FW_LOW_FORMAT 0x1C +#define K_FW_SET_RESET_FLAG 0x1E +#define K_FW_SPI_READ_10 0x21 +#define K_FW_SPI_WRITE_10 0x22 + +#define K_FW_SESSION 0X30 +#define K_FW_RESET 0xff + +#define CBW_DIRECTION_OUT 0x00 +#define CBW_DIRECTION_IN 0x80 + +struct cmd_dispatch_info { + int cmd; + void (*cb)(struct usb_ep *ep, struct usb_request *req); +}; + +static const struct cmd_dispatch_info cmd_dispatch_info[] = { + { + .cmd = K_FW_TEST_UNIT_READY, + .cb = cb_test_unit_ready, + }, + { + .cmd = K_FW_READ_FLASH_ID, + .cb = cb_read_storage_id, + }, + { + .cmd = K_FW_SET_DEVICE_ID, + .cb = cb_not_support, + }, + { + .cmd = K_FW_TEST_BAD_BLOCK, + .cb = cb_not_support, + }, + { + .cmd = K_FW_READ_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_WRITE_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_ERASE_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_WRITE_SPARE, + .cb = cb_not_support, + }, + { + .cmd = K_FW_READ_SPARE, + .cb = cb_not_support, + }, + { + .cmd = K_FW_ERASE_10_FORCE, + .cb = cb_not_support, + }, + { + .cmd = K_FW_GET_VERSION, + .cb = cb_not_support, + }, + { + .cmd = K_FW_LBA_READ_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_LBA_WRITE_10, + .cb = cb_write_lba, + }, + { + .cmd = K_FW_ERASE_SYS_DISK, + .cb = cb_not_support, + }, + { + .cmd = K_FW_SDRAM_READ_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_SDRAM_WRITE_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_SDRAM_EXECUTE, + .cb = cb_not_support, + }, + { + .cmd = K_FW_READ_FLASH_INFO, + .cb = cb_not_support, + }, + { + .cmd = K_FW_GET_CHIP_VER, + .cb = cb_not_support, + }, + { + .cmd = K_FW_LOW_FORMAT, + .cb = cb_not_support, + }, + { + .cmd = K_FW_SET_RESET_FLAG, + .cb = cb_not_support, + }, + { + .cmd = K_FW_SPI_READ_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_SPI_WRITE_10, + .cb = cb_not_support, + }, + { + .cmd = K_FW_SESSION, + .cb = cb_not_support, + }, + { + .cmd = K_FW_RESET, + .cb = cb_reboot, + }, +}; + + + +static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) +{ + void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; + struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN))); + int i; + char *cmdbuf = req->buf; + + if (req->status != 0 || req->length == 0) + return; + + memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN); + printcbw(req->buf); + + for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) { + if (cmd_dispatch_info[i].cmd == cbw.CDB[0]) { + func_cb = cmd_dispatch_info[i].cb; + break; + } + } + + if (!func_cb) { + error("unknown command: %s", (char*)req->buf); + rockusb_tx_write_str("FAILunknown command"); + } else { + if (req->actual < req->length) { + u8 *buf = (u8 *)req->buf; + buf[req->actual] = 0; + func_cb(ep, req); + } else { + error("buffer overflow"); + rockusb_tx_write_str("FAILbuffer overflow"); + } + } + + *cmdbuf = '\0'; + req->actual = 0; + usb_ep_queue(ep, req, 0); +}

Hi Eddie,
I recommend you to use ums framework instead of fastboot, because ums have dual-buffer which improve performance.
Thanks, - Kever On 03/15/2017 03:56 PM, Eddie Cai wrote:
this patch implement fastboot protocol on the device side. this is based on USB download gadget infrastructure. the rockusb function implements the rd, wl, rid commands. it can work with rkdeveloptool; https://github.com/rockchip-linux/rkdeveloptool
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 802 insertions(+) create mode 100644 drivers/usb/gadget/f_rockusb.c
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 0fbbb7c..0eb27a3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c new file mode 100644 index 0000000..a67cb35 --- /dev/null +++ b/drivers/usb/gadget/f_rockusb.c @@ -0,0 +1,801 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <config.h> +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> +#include <linux/compiler.h> +#include <version.h> +#include <g_dnl.h>
+#define ROCKUSB_VERSION "0.1"
+#define ROCKUSB_INTERFACE_CLASS 0xff +#define ROCKUSB_INTERFACE_SUB_CLASS 0x06 +#define ROCKUSB_INTERFACE_PROTOCOL 0x05
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200) +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040) +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+#define EP_BUFFER_SIZE 4096 +/*
- EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
- (64 or 512 or 1024), else we break on certain controllers like DWC3
- that expect bulk OUT requests to be divisible by maxpacket size.
- */
+struct f_rockusb {
- struct usb_function usb_function;
- /* IN/OUT EP's and corresponding requests */
- struct usb_ep *in_ep, *out_ep;
- struct usb_request *in_req, *out_req;
+};
+static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) +{
- return container_of(f, struct f_rockusb, usb_function);
+}
+static struct f_rockusb *rockusb_func;
+static struct usb_endpoint_descriptor fs_ep_in = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor fs_ep_out = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor hs_ep_in = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_endpoint_descriptor hs_ep_out = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_interface_descriptor interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0x00,
- .bAlternateSetting = 0x00,
- .bNumEndpoints = 0x02,
- .bInterfaceClass = ROCKUSB_INTERFACE_CLASS,
- .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS,
- .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL,
+};
+static struct usb_descriptor_header *rkusb_fs_function[] = {
- (struct usb_descriptor_header *)&interface_desc,
- (struct usb_descriptor_header *)&fs_ep_in,
- (struct usb_descriptor_header *)&fs_ep_out,
+};
+static struct usb_descriptor_header *rkusb_hs_function[] = {
- (struct usb_descriptor_header *)&interface_desc,
- (struct usb_descriptor_header *)&hs_ep_in,
- (struct usb_descriptor_header *)&hs_ep_out,
- NULL,
+};
+static struct usb_endpoint_descriptor * +rkusb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
+{
- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
- return fs;
+}
+/*
- static strings, in UTF-8
- */
+static const char rkusb_name[] = "Rockchip Rockusb";
+static struct usb_string rkusb_string_defs[] = {
- [0].s = rkusb_name,
- { } /* end of list */
+};
+static struct usb_gadget_strings stringtab_rkusb = {
- .language = 0x0409, /* en-us */
- .strings = rkusb_string_defs,
+};
+static struct usb_gadget_strings *rkusb_strings[] = {
- &stringtab_rkusb,
- NULL,
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); +static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size);
+static void rockusb_complete(struct usb_ep *ep, struct usb_request *req) +{
- int status = req->status;
- if (!status)
return;
- debug("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+}
+static int rockusb_bind(struct usb_configuration *c, struct usb_function *f) +{
- int id;
- struct usb_gadget *gadget = c->cdev->gadget;
- struct f_rockusb *f_rkusb = func_to_rockusb(f);
- const char *s;
- id = usb_interface_id(c, f);
- if (id < 0)
return id;
- interface_desc.bInterfaceNumber = id;
- id = usb_string_id(c->cdev);
- if (id < 0)
return id;
- rkusb_string_defs[0].id = id;
- interface_desc.iInterface = id;
- f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
- if (!f_rkusb->in_ep)
return -ENODEV;
- f_rkusb->in_ep->driver_data = c->cdev;
- f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
- if (!f_rkusb->out_ep)
return -ENODEV;
- f_rkusb->out_ep->driver_data = c->cdev;
- f->descriptors = rkusb_fs_function;
- if (gadget_is_dualspeed(gadget)) {
hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
f->hs_descriptors = rkusb_hs_function;
- }
- s = getenv("serial#");
- if (s)
g_dnl_set_serialnumber((char *)s);
- return 0;
+}
+static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f) +{
- memset(rockusb_func, 0, sizeof(*rockusb_func));
+}
+static void rockusb_disable(struct usb_function *f) +{
- struct f_rockusb *f_rkusb = func_to_rockusb(f);
- usb_ep_disable(f_rkusb->out_ep);
- usb_ep_disable(f_rkusb->in_ep);
- if (f_rkusb->out_req) {
free(f_rkusb->out_req->buf);
usb_ep_free_request(f_rkusb->out_ep, f_rkusb->out_req);
f_rkusb->out_req = NULL;
- }
- if (f_rkusb->in_req) {
free(f_rkusb->in_req->buf);
usb_ep_free_request(f_rkusb->in_ep, f_rkusb->in_req);
f_rkusb->in_req = NULL;
- }
+}
+static struct usb_request *rockusb_start_ep(struct usb_ep *ep) +{
- struct usb_request *req;
- req = usb_ep_alloc_request(ep, 0);
- if (!req)
return NULL;
- req->length = EP_BUFFER_SIZE;
- req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
- if (!req->buf) {
usb_ep_free_request(ep, req);
return NULL;
- }
- memset(req->buf, 0, req->length);
- return req;
+}
+static int rockusb_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
+{
- int ret;
- struct usb_composite_dev *cdev = f->config->cdev;
- struct usb_gadget *gadget = cdev->gadget;
- struct f_rockusb *f_rkusb = func_to_rockusb(f);
- const struct usb_endpoint_descriptor *d;
- debug("%s: func: %s intf: %d alt: %d\n",
__func__, f->name, interface, alt);
- d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
- ret = usb_ep_enable(f_rkusb->out_ep, d);
- if (ret) {
puts("failed to enable out ep\n");
return ret;
- }
- f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep);
- if (!f_rkusb->out_req) {
puts("failed to alloc out req\n");
ret = -EINVAL;
goto err;
- }
- f_rkusb->out_req->complete = rx_handler_command;
- d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
- ret = usb_ep_enable(f_rkusb->in_ep, d);
- if (ret) {
puts("failed to enable in ep\n");
goto err;
- }
- f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep);
- if (!f_rkusb->in_req) {
puts("failed alloc req in\n");
ret = -EINVAL;
goto err;
- }
- f_rkusb->in_req->complete = rockusb_complete;
- ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0);
- if (ret)
goto err;
- return 0;
+err:
- rockusb_disable(f);
- return ret;
+}
+static int rockusb_add(struct usb_configuration *c) +{
- struct f_rockusb *f_rkusb = rockusb_func;
- int status;
- debug("%s: cdev: 0x%p\n", __func__, c->cdev);
- if (!f_rkusb) {
f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_rkusb));
if (!f_rkusb)
return -ENOMEM;
rockusb_func = f_rkusb;
memset(f_rkusb, 0, sizeof(*f_rkusb));
- }
- f_rkusb->usb_function.name = "f_rockusb";
- f_rkusb->usb_function.bind = rockusb_bind;
- f_rkusb->usb_function.unbind = rockusb_unbind;
- f_rkusb->usb_function.set_alt = rockusb_set_alt;
- f_rkusb->usb_function.disable = rockusb_disable;
- f_rkusb->usb_function.strings = rkusb_strings;
- status = usb_add_function(c, &f_rkusb->usb_function);
- if (status) {
free(f_rkusb);
rockusb_func = f_rkusb;
- }
- return status;
+}
+char *rockusb_dev_type = 0; +int rockusb_dev_index = 0;
+void rockusb_dev_init(char *dev_type, int dev_index) +{
- rockusb_dev_type = dev_type;
- rockusb_dev_index = dev_index;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add);
+static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) +{
- struct usb_request *in_req = rockusb_func->in_req;
- int ret;
- memcpy(in_req->buf, buffer, buffer_size);
- in_req->length = buffer_size;
- usb_ep_dequeue(rockusb_func->in_ep, in_req);
- ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0);
- if (ret)
printf("Error %d on queue\n", ret);
- return 0;
+}
+static int rockusb_tx_write_str(const char *buffer) +{
- return rockusb_tx_write(buffer, strlen(buffer));
+}
+/* Bulk-only data structures */
+/* Command Block Wrapper */ +struct fsg_bulk_cb_wrap {
- __le32 Signature; /* Contains 'USBC' */
- u32 Tag; /* Unique per command id */
- __le32 DataTransferLength; /* Size of the data */
- u8 Flags; /* Direction in bit 7 */
- u8 Lun; /* LUN (normally 0) */
- u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */
- u8 CDB[16]; /* Command Data Block */
+};
+#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80
+/* Command Status Wrapper */ +struct bulk_cs_wrap {
- __le32 Signature; /* Should = 'USBS' */
- u32 Tag; /* Same as original command */
- __le32 Residue; /* Amount not transferred */
- u8 Status; /* See below */
+};
+#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2
+#define CSW_GOOD 0x00 +#define CSW_FAIL 0x01
+static void printcbw(char *buf) +{
- struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- memcpy((char*)&cbw, buf, USB_BULK_CB_WRAP_LEN);
- debug("cbw: Signature:%x\n", cbw.Signature);
- debug("cbw: Tag=%x\n", cbw.Tag);
- debug("cbw: DataTransferLength=%d\n", cbw.DataTransferLength);
- debug("cbw: Flags=%x\n", cbw.Flags);
- debug("cbw: Lun=%d\n", cbw.Lun);
- debug("cbw: Length=%d\n", cbw.Length);
- debug("cbw: ucOperCode=%x\n", cbw.CDB[0]);
- debug("cbw: ucReserved=%x\n", cbw.CDB[1]);
- debug("cbw: dwAddress:%x %x %x %x\n", cbw.CDB[5], cbw.CDB[4],
cbw.CDB[3], cbw.CDB[2]);
- debug("cbw: ucReserved2=%x\n", cbw.CDB[6]);
- debug("cbw: usLength:%x %x\n", cbw.CDB[8], cbw.CDB[7]);
+}
+static void printcsw(char *buf) +{
- struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- memcpy((char*)&csw, buf, USB_BULK_CS_WRAP_LEN);
- debug("csw: Signature:%x\n", csw.Signature);
- debug("csw: Tag:%x\n", csw.Tag);
- debug("csw: Residue:%x\n", csw.Residue);
- debug("csw: Status:%x\n", csw.Status);
+}
+static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size) +{
- struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- csw.Signature = cpu_to_le32(USB_BULK_CS_SIG);
- csw.Tag = Tag;
- csw.Residue = cpu_to_be32(residue);
- csw.Status = Status;
- printcsw((char*)&csw);
- return rockusb_tx_write((char*)&csw, size);
+}
+int download_tag = 0; +int download_lba = 0; +static unsigned int download_size; +static unsigned int download_bytes; +struct blk_desc *download_desc = 0;
+static unsigned int rx_bytes_expected(struct usb_ep *ep) +{
- int rx_remain = download_size - download_bytes;
- unsigned int rem;
- unsigned int maxpacket = ep->maxpacket;
- if (rx_remain <= 0)
return 0;
- else if (rx_remain > EP_BUFFER_SIZE)
return EP_BUFFER_SIZE;
- rem = rx_remain % maxpacket;
- if (rem > 0)
rx_remain = rx_remain + (maxpacket - rem);
- return rx_remain;
+}
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) +{
- unsigned int transfer_size = download_size - download_bytes;
- const unsigned char *buffer = req->buf;
- unsigned int buffer_size = req->actual;
- if(!download_desc){
printf("rx_handler_dl_image blk_get_dev\n");
download_desc = blk_get_dev(rockusb_dev_type, rockusb_dev_index);
if (!download_desc || download_desc->type == DEV_TYPE_UNKNOWN){
error("invalid mmc device\n");
rockusb_tx_write_csw(download_tag, 0, CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
- }
- if (req->status != 0) {
printf("Bad status: %d\n", req->status);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL, USB_BULK_CS_WRAP_LEN);
return;
- }
- if (buffer_size < transfer_size)
transfer_size = buffer_size;
- memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
buffer, transfer_size);
- download_bytes += transfer_size;
- /* Check if transfer is done */
- if (download_bytes >= download_size) {
int blks = 0, blkcnt = download_size/512;
printf("download %d bytes finished, start writing to lba %x\n",
download_bytes, download_lba);
blks = blk_dwrite(download_desc, download_lba, blkcnt,
(char*)CONFIG_FASTBOOT_BUF_ADDR);
if (blks != blkcnt) {
error("failed writing to device %s: %d\n",
rockusb_dev_type, rockusb_dev_index);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL, USB_BULK_CS_WRAP_LEN);
return;
}
req->complete = rx_handler_command;
req->length = EP_BUFFER_SIZE;
download_size = 0;
printf("done\n");
rockusb_tx_write_csw(download_tag, 0, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
- } else {
req->length = rx_bytes_expected(ep);
- }
- req->actual = 0;
- usb_ep_queue(ep, req, 0);
+}
+static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD, USB_BULK_CS_WRAP_LEN);
+}
+static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- char emmc_id[] = "EMMC ";
- printf("cb_read_storage_id\n");
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- rockusb_tx_write_str(emmc_id);//only support emmc now
- rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- int sector_count;
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- sector_count = (int)get_unaligned_be16(&cbw.CDB[7]);
- download_lba = get_unaligned_be32(&cbw.CDB[2]);
- download_size = sector_count * 512;
- download_bytes = 0;
- download_tag = cbw.Tag;
- if ((0 == download_size) || (download_size>CONFIG_FASTBOOT_BUF_SIZE)){
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_FAIL, USB_BULK_CS_WRAP_LEN);
- } else {
req->complete = rx_handler_dl_image;
req->length = rx_bytes_expected(ep);
- }
+}
+static int reboot_flag;
+int __weak rkusb_set_reboot_flag(int flag) +{
- printf("rkusb_set_reboot_flag: %d\n", reboot_flag);
- return -ENOSYS;
+}
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) +{
- rkusb_set_reboot_flag(reboot_flag);
- do_reset(NULL, 0, 0, NULL);
+}
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- reboot_flag = 0;
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- reboot_flag = cbw.CDB[1];
- rockusb_func->in_req->complete = compl_do_reset;
- rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_not_support(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- printf("Rockusb command %x not support yet\n", cbw.CDB[0]);
- rockusb_tx_write_csw(cbw.Tag, 0, CSW_FAIL, USB_BULK_CS_WRAP_LEN);
+}
+#define RKUSB_STATUS_IDLE 0 +#define RKUSB_STATUS_CMD 1 +#define RKUSB_STATUS_RXDATA 2 +#define RKUSB_STATUS_TXDATA 3 +#define RKUSB_STATUS_CSW 4 +#define RKUSB_STATUS_RXDATA_PREPARE 5 +#define RKUSB_STATUS_TXDATA_PREPARE 6
+typedef enum {
TEST_UNIT_READY = 0,
READ_FLASH_ID = 0x01,
TEST_BAD_BLOCK = 0x03,
READ_SECTOR = 0x04,
WRITE_SECTOR = 0x05,
ERASE_NORMAL = 0x06,
ERASE_FORCE = 0x0B,
READ_LBA = 0x14,
WRITE_LBA = 0x15,
ERASE_SYSTEMDISK = 0x16,
READ_SDRAM = 0x17,
WRITE_SDRAM = 0x18,
EXECUTE_SDRAM = 0x19,
READ_FLASH_INFO = 0x1A,
READ_CHIP_INFO = 0x1B,
SET_RESET_FLAG = 0x1E,
WRITE_EFUSE = 0x1F,
READ_EFUSE = 0x20,
READ_SPI_FLASH = 0x21,
WRITE_SPI_FLASH = 0x22,
WRITE_NEW_EFUSE = 0x23,
READ_NEW_EFUSE = 0x24,
DEVICE_RESET = 0xFF
+} USB_OPERATION_CODE;
+#define K_FW_TEST_UNIT_READY 0x00 +#define K_FW_READ_FLASH_ID 0x01 +#define K_FW_SET_DEVICE_ID 0x02 +#define K_FW_TEST_BAD_BLOCK 0x03 +#define K_FW_READ_10 0x04 +#define K_FW_WRITE_10 0x05 +#define K_FW_ERASE_10 0x06 +#define K_FW_WRITE_SPARE 0x07 +#define K_FW_READ_SPARE 0x08
+#define K_FW_ERASE_10_FORCE 0x0b +#define K_FW_GET_VERSION 0x0c
+#define K_FW_LBA_READ_10 0x14 +#define K_FW_LBA_WRITE_10 0x15 +#define K_FW_ERASE_SYS_DISK 0x16 +#define K_FW_SDRAM_READ_10 0x17 +#define K_FW_SDRAM_WRITE_10 0x18 +#define K_FW_SDRAM_EXECUTE 0x19 +#define K_FW_READ_FLASH_INFO 0x1A +#define K_FW_GET_CHIP_VER 0x1B +#define K_FW_LOW_FORMAT 0x1C +#define K_FW_SET_RESET_FLAG 0x1E +#define K_FW_SPI_READ_10 0x21 +#define K_FW_SPI_WRITE_10 0x22
+#define K_FW_SESSION 0X30 +#define K_FW_RESET 0xff
+#define CBW_DIRECTION_OUT 0x00 +#define CBW_DIRECTION_IN 0x80
+struct cmd_dispatch_info {
- int cmd;
- void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
- {
.cmd = K_FW_TEST_UNIT_READY,
.cb = cb_test_unit_ready,
- },
- {
.cmd = K_FW_READ_FLASH_ID,
.cb = cb_read_storage_id,
- },
- {
.cmd = K_FW_SET_DEVICE_ID,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_TEST_BAD_BLOCK,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_WRITE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_ERASE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_WRITE_SPARE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_READ_SPARE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_ERASE_10_FORCE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_GET_VERSION,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_LBA_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_LBA_WRITE_10,
.cb = cb_write_lba,
- },
- {
.cmd = K_FW_ERASE_SYS_DISK,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SDRAM_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SDRAM_WRITE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SDRAM_EXECUTE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_READ_FLASH_INFO,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_GET_CHIP_VER,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_LOW_FORMAT,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SET_RESET_FLAG,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SPI_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SPI_WRITE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SESSION,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_RESET,
.cb = cb_reboot,
- },
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) +{
- void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
- struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DMA_MINALIGN)));
- int i;
- char *cmdbuf = req->buf;
- if (req->status != 0 || req->length == 0)
return;
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- printcbw(req->buf);
- for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
if (cmd_dispatch_info[i].cmd == cbw.CDB[0]) {
func_cb = cmd_dispatch_info[i].cb;
break;
}
- }
- if (!func_cb) {
error("unknown command: %s", (char*)req->buf);
rockusb_tx_write_str("FAILunknown command");
- } else {
if (req->actual < req->length) {
u8 *buf = (u8 *)req->buf;
buf[req->actual] = 0;
func_cb(ep, req);
} else {
error("buffer overflow");
rockusb_tx_write_str("FAILbuffer overflow");
}
- }
- *cmdbuf = '\0';
- req->actual = 0;
- usb_ep_queue(ep, req, 0);
+}

2017-03-16 15:05 GMT+08:00 Kever Yang kever.yang@rock-chips.com:
Hi Eddie,
I recommend you to use ums framework instead of fastboot, because
ums have dual-buffer which improve performance.
I will try to add dual buffer support in next version
Thanks,
- Kever
On 03/15/2017 03:56 PM, Eddie Cai wrote:
this patch implement fastboot protocol on the device side. this is based on USB download gadget infrastructure. the rockusb function implements the rd, wl, rid commands. it can work with rkdeveloptool; https://github.com/rockchip-linux/rkdeveloptool
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++ +++++++++++ 2 files changed, 802 insertions(+) create mode 100644 drivers/usb/gadget/f_rockusb.c
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 0fbbb7c..0eb27a3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c new file mode 100644 index 0000000..a67cb35 --- /dev/null +++ b/drivers/usb/gadget/f_rockusb.c @@ -0,0 +1,801 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <config.h> +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> +#include <linux/compiler.h> +#include <version.h> +#include <g_dnl.h>
+#define ROCKUSB_VERSION "0.1"
+#define ROCKUSB_INTERFACE_CLASS 0xff +#define ROCKUSB_INTERFACE_SUB_CLASS 0x06 +#define ROCKUSB_INTERFACE_PROTOCOL 0x05
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200) +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040) +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+#define EP_BUFFER_SIZE 4096 +/*
- EP_BUFFER_SIZE must always be an integral multiple of maxpacket size
- (64 or 512 or 1024), else we break on certain controllers like DWC3
- that expect bulk OUT requests to be divisible by maxpacket size.
- */
+struct f_rockusb {
struct usb_function usb_function;
/* IN/OUT EP's and corresponding requests */
struct usb_ep *in_ep, *out_ep;
struct usb_request *in_req, *out_req;
+};
+static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) +{
return container_of(f, struct f_rockusb, usb_function);
+}
+static struct f_rockusb *rockusb_func;
+static struct usb_endpoint_descriptor fs_ep_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor fs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor hs_ep_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_endpoint_descriptor hs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_interface_descriptor interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = ROCKUSB_INTERFACE_CLASS,
.bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS,
.bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL,
+};
+static struct usb_descriptor_header *rkusb_fs_function[] = {
(struct usb_descriptor_header *)&interface_desc,
(struct usb_descriptor_header *)&fs_ep_in,
(struct usb_descriptor_header *)&fs_ep_out,
+};
+static struct usb_descriptor_header *rkusb_hs_function[] = {
(struct usb_descriptor_header *)&interface_desc,
(struct usb_descriptor_header *)&hs_ep_in,
(struct usb_descriptor_header *)&hs_ep_out,
NULL,
+};
+static struct usb_endpoint_descriptor * +rkusb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
+{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
+}
+/*
- static strings, in UTF-8
- */
+static const char rkusb_name[] = "Rockchip Rockusb";
+static struct usb_string rkusb_string_defs[] = {
[0].s = rkusb_name,
{ } /* end of list */
+};
+static struct usb_gadget_strings stringtab_rkusb = {
.language = 0x0409, /* en-us */
.strings = rkusb_string_defs,
+};
+static struct usb_gadget_strings *rkusb_strings[] = {
&stringtab_rkusb,
NULL,
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); +static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size);
+static void rockusb_complete(struct usb_ep *ep, struct usb_request *req) +{
int status = req->status;
if (!status)
return;
debug("status: %d ep '%s' trans: %d\n", status, ep->name,
req->actual); +}
+static int rockusb_bind(struct usb_configuration *c, struct usb_function *f) +{
int id;
struct usb_gadget *gadget = c->cdev->gadget;
struct f_rockusb *f_rkusb = func_to_rockusb(f);
const char *s;
id = usb_interface_id(c, f);
if (id < 0)
return id;
interface_desc.bInterfaceNumber = id;
id = usb_string_id(c->cdev);
if (id < 0)
return id;
rkusb_string_defs[0].id = id;
interface_desc.iInterface = id;
f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
if (!f_rkusb->in_ep)
return -ENODEV;
f_rkusb->in_ep->driver_data = c->cdev;
f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
if (!f_rkusb->out_ep)
return -ENODEV;
f_rkusb->out_ep->driver_data = c->cdev;
f->descriptors = rkusb_fs_function;
if (gadget_is_dualspeed(gadget)) {
hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
f->hs_descriptors = rkusb_hs_function;
}
s = getenv("serial#");
if (s)
g_dnl_set_serialnumber((char *)s);
return 0;
+}
+static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f) +{
memset(rockusb_func, 0, sizeof(*rockusb_func));
+}
+static void rockusb_disable(struct usb_function *f) +{
struct f_rockusb *f_rkusb = func_to_rockusb(f);
usb_ep_disable(f_rkusb->out_ep);
usb_ep_disable(f_rkusb->in_ep);
if (f_rkusb->out_req) {
free(f_rkusb->out_req->buf);
usb_ep_free_request(f_rkusb->out_ep, f_rkusb->out_req);
f_rkusb->out_req = NULL;
}
if (f_rkusb->in_req) {
free(f_rkusb->in_req->buf);
usb_ep_free_request(f_rkusb->in_ep, f_rkusb->in_req);
f_rkusb->in_req = NULL;
}
+}
+static struct usb_request *rockusb_start_ep(struct usb_ep *ep) +{
struct usb_request *req;
req = usb_ep_alloc_request(ep, 0);
if (!req)
return NULL;
req->length = EP_BUFFER_SIZE;
req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
if (!req->buf) {
usb_ep_free_request(ep, req);
return NULL;
}
memset(req->buf, 0, req->length);
return req;
+}
+static int rockusb_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
+{
int ret;
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct f_rockusb *f_rkusb = func_to_rockusb(f);
const struct usb_endpoint_descriptor *d;
debug("%s: func: %s intf: %d alt: %d\n",
__func__, f->name, interface, alt);
d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
ret = usb_ep_enable(f_rkusb->out_ep, d);
if (ret) {
puts("failed to enable out ep\n");
return ret;
}
f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep);
if (!f_rkusb->out_req) {
puts("failed to alloc out req\n");
ret = -EINVAL;
goto err;
}
f_rkusb->out_req->complete = rx_handler_command;
d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
ret = usb_ep_enable(f_rkusb->in_ep, d);
if (ret) {
puts("failed to enable in ep\n");
goto err;
}
f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep);
if (!f_rkusb->in_req) {
puts("failed alloc req in\n");
ret = -EINVAL;
goto err;
}
f_rkusb->in_req->complete = rockusb_complete;
ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0);
if (ret)
goto err;
return 0;
+err:
rockusb_disable(f);
return ret;
+}
+static int rockusb_add(struct usb_configuration *c) +{
struct f_rockusb *f_rkusb = rockusb_func;
int status;
debug("%s: cdev: 0x%p\n", __func__, c->cdev);
if (!f_rkusb) {
f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE,
sizeof(*f_rkusb));
if (!f_rkusb)
return -ENOMEM;
rockusb_func = f_rkusb;
memset(f_rkusb, 0, sizeof(*f_rkusb));
}
f_rkusb->usb_function.name = "f_rockusb";
f_rkusb->usb_function.bind = rockusb_bind;
f_rkusb->usb_function.unbind = rockusb_unbind;
f_rkusb->usb_function.set_alt = rockusb_set_alt;
f_rkusb->usb_function.disable = rockusb_disable;
f_rkusb->usb_function.strings = rkusb_strings;
status = usb_add_function(c, &f_rkusb->usb_function);
if (status) {
free(f_rkusb);
rockusb_func = f_rkusb;
}
return status;
+}
+char *rockusb_dev_type = 0; +int rockusb_dev_index = 0;
+void rockusb_dev_init(char *dev_type, int dev_index) +{
rockusb_dev_type = dev_type;
rockusb_dev_index = dev_index;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add);
+static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) +{
struct usb_request *in_req = rockusb_func->in_req;
int ret;
memcpy(in_req->buf, buffer, buffer_size);
in_req->length = buffer_size;
usb_ep_dequeue(rockusb_func->in_ep, in_req);
ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0);
if (ret)
printf("Error %d on queue\n", ret);
return 0;
+}
+static int rockusb_tx_write_str(const char *buffer) +{
return rockusb_tx_write(buffer, strlen(buffer));
+}
+/* Bulk-only data structures */
+/* Command Block Wrapper */ +struct fsg_bulk_cb_wrap {
__le32 Signature; /* Contains 'USBC' */
u32 Tag; /* Unique per command id */
__le32 DataTransferLength; /* Size of the data */
u8 Flags; /* Direction in bit 7 */
u8 Lun; /* LUN (normally 0) */
u8 Length; /* Of the CDB, <=
MAX_COMMAND_SIZE */
u8 CDB[16]; /* Command Data Block */
+};
+#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80
+/* Command Status Wrapper */ +struct bulk_cs_wrap {
__le32 Signature; /* Should = 'USBS' */
u32 Tag; /* Same as original command */
__le32 Residue; /* Amount not transferred */
u8 Status; /* See below */
+};
+#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2
+#define CSW_GOOD 0x00 +#define CSW_FAIL 0x01
+static void printcbw(char *buf) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, buf, USB_BULK_CB_WRAP_LEN);
debug("cbw: Signature:%x\n", cbw.Signature);
debug("cbw: Tag=%x\n", cbw.Tag);
debug("cbw: DataTransferLength=%d\n", cbw.DataTransferLength);
debug("cbw: Flags=%x\n", cbw.Flags);
debug("cbw: Lun=%d\n", cbw.Lun);
debug("cbw: Length=%d\n", cbw.Length);
debug("cbw: ucOperCode=%x\n", cbw.CDB[0]);
debug("cbw: ucReserved=%x\n", cbw.CDB[1]);
debug("cbw: dwAddress:%x %x %x %x\n", cbw.CDB[5], cbw.CDB[4],
cbw.CDB[3], cbw.CDB[2]);
debug("cbw: ucReserved2=%x\n", cbw.CDB[6]);
debug("cbw: usLength:%x %x\n", cbw.CDB[8], cbw.CDB[7]);
+}
+static void printcsw(char *buf) +{
struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&csw, buf, USB_BULK_CS_WRAP_LEN);
debug("csw: Signature:%x\n", csw.Signature);
debug("csw: Tag:%x\n", csw.Tag);
debug("csw: Residue:%x\n", csw.Residue);
debug("csw: Status:%x\n", csw.Status);
+}
+static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size) +{
struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
csw.Signature = cpu_to_le32(USB_BULK_CS_SIG);
csw.Tag = Tag;
csw.Residue = cpu_to_be32(residue);
csw.Status = Status;
printcsw((char*)&csw);
return rockusb_tx_write((char*)&csw, size);
+}
+int download_tag = 0; +int download_lba = 0; +static unsigned int download_size; +static unsigned int download_bytes; +struct blk_desc *download_desc = 0;
+static unsigned int rx_bytes_expected(struct usb_ep *ep) +{
int rx_remain = download_size - download_bytes;
unsigned int rem;
unsigned int maxpacket = ep->maxpacket;
if (rx_remain <= 0)
return 0;
else if (rx_remain > EP_BUFFER_SIZE)
return EP_BUFFER_SIZE;
rem = rx_remain % maxpacket;
if (rem > 0)
rx_remain = rx_remain + (maxpacket - rem);
return rx_remain;
+}
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) +{
unsigned int transfer_size = download_size - download_bytes;
const unsigned char *buffer = req->buf;
unsigned int buffer_size = req->actual;
if(!download_desc){
printf("rx_handler_dl_image blk_get_dev\n");
download_desc = blk_get_dev(rockusb_dev_type,
rockusb_dev_index);
if (!download_desc || download_desc->type ==
DEV_TYPE_UNKNOWN){
error("invalid mmc device\n");
rockusb_tx_write_csw(download_tag, 0, CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
}
if (req->status != 0) {
printf("Bad status: %d\n", req->status);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL, USB_BULK_CS_WRAP_LEN);
return;
}
if (buffer_size < transfer_size)
transfer_size = buffer_size;
memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
buffer, transfer_size);
download_bytes += transfer_size;
/* Check if transfer is done */
if (download_bytes >= download_size) {
int blks = 0, blkcnt = download_size/512;
printf("download %d bytes finished, start writing to lba
%x\n",
download_bytes, download_lba);
blks = blk_dwrite(download_desc, download_lba, blkcnt,
(char*)CONFIG_FASTBOOT_BUF_ADDR);
if (blks != blkcnt) {
error("failed writing to device %s: %d\n",
rockusb_dev_type, rockusb_dev_index);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
req->complete = rx_handler_command;
req->length = EP_BUFFER_SIZE;
download_size = 0;
printf("done\n");
rockusb_tx_write_csw(download_tag, 0, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
} else {
req->length = rx_bytes_expected(ep);
}
req->actual = 0;
usb_ep_queue(ep, req, 0);
+}
+static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD, USB_BULK_CS_WRAP_LEN);
+}
+static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
char emmc_id[] = "EMMC ";
printf("cb_read_storage_id\n");
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
rockusb_tx_write_str(emmc_id);//only support emmc now
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
int sector_count;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
sector_count = (int)get_unaligned_be16(&cbw.CDB[7]);
download_lba = get_unaligned_be32(&cbw.CDB[2]);
download_size = sector_count * 512;
download_bytes = 0;
download_tag = cbw.Tag;
if ((0 == download_size) || (download_size>CONFIG_FASTBOOT
_BUF_SIZE)){
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_FAIL, USB_BULK_CS_WRAP_LEN);
} else {
req->complete = rx_handler_dl_image;
req->length = rx_bytes_expected(ep);
}
+}
+static int reboot_flag;
+int __weak rkusb_set_reboot_flag(int flag) +{
printf("rkusb_set_reboot_flag: %d\n", reboot_flag);
return -ENOSYS;
+}
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) +{
rkusb_set_reboot_flag(reboot_flag);
do_reset(NULL, 0, 0, NULL);
+}
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
reboot_flag = 0;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
reboot_flag = cbw.CDB[1];
rockusb_func->in_req->complete = compl_do_reset;
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_not_support(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
printf("Rockusb command %x not support yet\n", cbw.CDB[0]);
rockusb_tx_write_csw(cbw.Tag, 0, CSW_FAIL, USB_BULK_CS_WRAP_LEN);
+}
+#define RKUSB_STATUS_IDLE 0 +#define RKUSB_STATUS_CMD 1 +#define RKUSB_STATUS_RXDATA 2 +#define RKUSB_STATUS_TXDATA 3 +#define RKUSB_STATUS_CSW 4 +#define RKUSB_STATUS_RXDATA_PREPARE 5 +#define RKUSB_STATUS_TXDATA_PREPARE 6
+typedef enum {
TEST_UNIT_READY = 0,
READ_FLASH_ID = 0x01,
TEST_BAD_BLOCK = 0x03,
READ_SECTOR = 0x04,
WRITE_SECTOR = 0x05,
ERASE_NORMAL = 0x06,
ERASE_FORCE = 0x0B,
READ_LBA = 0x14,
WRITE_LBA = 0x15,
ERASE_SYSTEMDISK = 0x16,
READ_SDRAM = 0x17,
WRITE_SDRAM = 0x18,
EXECUTE_SDRAM = 0x19,
READ_FLASH_INFO = 0x1A,
READ_CHIP_INFO = 0x1B,
SET_RESET_FLAG = 0x1E,
WRITE_EFUSE = 0x1F,
READ_EFUSE = 0x20,
READ_SPI_FLASH = 0x21,
WRITE_SPI_FLASH = 0x22,
WRITE_NEW_EFUSE = 0x23,
READ_NEW_EFUSE = 0x24,
DEVICE_RESET = 0xFF
+} USB_OPERATION_CODE;
+#define K_FW_TEST_UNIT_READY 0x00 +#define K_FW_READ_FLASH_ID 0x01 +#define K_FW_SET_DEVICE_ID 0x02 +#define K_FW_TEST_BAD_BLOCK 0x03 +#define K_FW_READ_10 0x04 +#define K_FW_WRITE_10 0x05 +#define K_FW_ERASE_10 0x06 +#define K_FW_WRITE_SPARE 0x07 +#define K_FW_READ_SPARE 0x08
+#define K_FW_ERASE_10_FORCE 0x0b +#define K_FW_GET_VERSION 0x0c
+#define K_FW_LBA_READ_10 0x14 +#define K_FW_LBA_WRITE_10 0x15 +#define K_FW_ERASE_SYS_DISK 0x16 +#define K_FW_SDRAM_READ_10 0x17 +#define K_FW_SDRAM_WRITE_10 0x18 +#define K_FW_SDRAM_EXECUTE 0x19 +#define K_FW_READ_FLASH_INFO 0x1A +#define K_FW_GET_CHIP_VER 0x1B +#define K_FW_LOW_FORMAT 0x1C +#define K_FW_SET_RESET_FLAG 0x1E +#define K_FW_SPI_READ_10 0x21 +#define K_FW_SPI_WRITE_10 0x22
+#define K_FW_SESSION 0X30 +#define K_FW_RESET 0xff
+#define CBW_DIRECTION_OUT 0x00 +#define CBW_DIRECTION_IN 0x80
+struct cmd_dispatch_info {
int cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
{
.cmd = K_FW_TEST_UNIT_READY,
.cb = cb_test_unit_ready,
},
{
.cmd = K_FW_READ_FLASH_ID,
.cb = cb_read_storage_id,
},
{
.cmd = K_FW_SET_DEVICE_ID,
.cb = cb_not_support,
},
{
.cmd = K_FW_TEST_BAD_BLOCK,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_ERASE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_WRITE_SPARE,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_SPARE,
.cb = cb_not_support,
},
{
.cmd = K_FW_ERASE_10_FORCE,
.cb = cb_not_support,
},
{
.cmd = K_FW_GET_VERSION,
.cb = cb_not_support,
},
{
.cmd = K_FW_LBA_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_LBA_WRITE_10,
.cb = cb_write_lba,
},
{
.cmd = K_FW_ERASE_SYS_DISK,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_EXECUTE,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_FLASH_INFO,
.cb = cb_not_support,
},
{
.cmd = K_FW_GET_CHIP_VER,
.cb = cb_not_support,
},
{
.cmd = K_FW_LOW_FORMAT,
.cb = cb_not_support,
},
{
.cmd = K_FW_SET_RESET_FLAG,
.cb = cb_not_support,
},
{
.cmd = K_FW_SPI_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SPI_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SESSION,
.cb = cb_not_support,
},
{
.cmd = K_FW_RESET,
.cb = cb_reboot,
},
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) +{
void (*func_cb)(struct usb_ep *ep, struct usb_request *req) =
NULL;
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
int i;
char *cmdbuf = req->buf;
if (req->status != 0 || req->length == 0)
return;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
printcbw(req->buf);
for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
if (cmd_dispatch_info[i].cmd == cbw.CDB[0]) {
func_cb = cmd_dispatch_info[i].cb;
break;
}
}
if (!func_cb) {
error("unknown command: %s", (char*)req->buf);
rockusb_tx_write_str("FAILunknown command");
} else {
if (req->actual < req->length) {
u8 *buf = (u8 *)req->buf;
buf[req->actual] = 0;
func_cb(ep, req);
} else {
error("buffer overflow");
rockusb_tx_write_str("FAILbuffer overflow");
}
}
*cmdbuf = '\0';
req->actual = 0;
usb_ep_queue(ep, req, 0);
+}

Hi Eddie,
2017-03-16 15:05 GMT+08:00 Kever Yang kever.yang@rock-chips.com:
Hi Eddie,
I recommend you to use ums framework instead of fastboot,
because ums have dual-buffer which improve performance.
I will try to add dual buffer support in next version
If of course possible - please reuse as much code as possible.
Thanks,
- Kever
On 03/15/2017 03:56 PM, Eddie Cai wrote:
this patch implement fastboot protocol on the device side. this is based on USB download gadget infrastructure. the rockusb function implements the rd, wl, rid commands. it can work with rkdeveloptool; https://github.com/rockchip-linux/rkdeveloptool
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++ +++++++++++ 2 files changed, 802 insertions(+) create mode 100644 drivers/usb/gadget/f_rockusb.c
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 0fbbb7c..0eb27a3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c new file mode 100644 index 0000000..a67cb35 --- /dev/null +++ b/drivers/usb/gadget/f_rockusb.c @@ -0,0 +1,801 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <config.h> +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> +#include <linux/compiler.h> +#include <version.h> +#include <g_dnl.h>
+#define ROCKUSB_VERSION "0.1"
+#define ROCKUSB_INTERFACE_CLASS 0xff +#define ROCKUSB_INTERFACE_SUB_CLASS 0x06 +#define ROCKUSB_INTERFACE_PROTOCOL 0x05
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200) +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040) +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+#define EP_BUFFER_SIZE 4096 +/*
- EP_BUFFER_SIZE must always be an integral multiple of
maxpacket size
- (64 or 512 or 1024), else we break on certain controllers like
DWC3
- that expect bulk OUT requests to be divisible by maxpacket
size.
- */
+struct f_rockusb {
struct usb_function usb_function;
/* IN/OUT EP's and corresponding requests */
struct usb_ep *in_ep, *out_ep;
struct usb_request *in_req, *out_req;
+};
+static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) +{
return container_of(f, struct f_rockusb, usb_function);
+}
+static struct f_rockusb *rockusb_func;
+static struct usb_endpoint_descriptor fs_ep_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor fs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor hs_ep_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_endpoint_descriptor hs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_interface_descriptor interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = ROCKUSB_INTERFACE_CLASS,
.bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS,
.bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL,
+};
+static struct usb_descriptor_header *rkusb_fs_function[] = {
(struct usb_descriptor_header *)&interface_desc,
(struct usb_descriptor_header *)&fs_ep_in,
(struct usb_descriptor_header *)&fs_ep_out,
+};
+static struct usb_descriptor_header *rkusb_hs_function[] = {
(struct usb_descriptor_header *)&interface_desc,
(struct usb_descriptor_header *)&hs_ep_in,
(struct usb_descriptor_header *)&hs_ep_out,
NULL,
+};
+static struct usb_endpoint_descriptor * +rkusb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
+{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
+}
+/*
- static strings, in UTF-8
- */
+static const char rkusb_name[] = "Rockchip Rockusb";
+static struct usb_string rkusb_string_defs[] = {
[0].s = rkusb_name,
{ } /* end of list */
+};
+static struct usb_gadget_strings stringtab_rkusb = {
.language = 0x0409, /* en-us */
.strings = rkusb_string_defs,
+};
+static struct usb_gadget_strings *rkusb_strings[] = {
&stringtab_rkusb,
NULL,
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); +static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size);
+static void rockusb_complete(struct usb_ep *ep, struct usb_request *req) +{
int status = req->status;
if (!status)
return;
debug("status: %d ep '%s' trans: %d\n", status, ep->name,
req->actual); +}
+static int rockusb_bind(struct usb_configuration *c, struct usb_function *f) +{
int id;
struct usb_gadget *gadget = c->cdev->gadget;
struct f_rockusb *f_rkusb = func_to_rockusb(f);
const char *s;
id = usb_interface_id(c, f);
if (id < 0)
return id;
interface_desc.bInterfaceNumber = id;
id = usb_string_id(c->cdev);
if (id < 0)
return id;
rkusb_string_defs[0].id = id;
interface_desc.iInterface = id;
f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
if (!f_rkusb->in_ep)
return -ENODEV;
f_rkusb->in_ep->driver_data = c->cdev;
f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
if (!f_rkusb->out_ep)
return -ENODEV;
f_rkusb->out_ep->driver_data = c->cdev;
f->descriptors = rkusb_fs_function;
if (gadget_is_dualspeed(gadget)) {
hs_ep_in.bEndpointAddress =
fs_ep_in.bEndpointAddress;
hs_ep_out.bEndpointAddress =
fs_ep_out.bEndpointAddress;
f->hs_descriptors = rkusb_hs_function;
}
s = getenv("serial#");
if (s)
g_dnl_set_serialnumber((char *)s);
return 0;
+}
+static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f) +{
memset(rockusb_func, 0, sizeof(*rockusb_func));
+}
+static void rockusb_disable(struct usb_function *f) +{
struct f_rockusb *f_rkusb = func_to_rockusb(f);
usb_ep_disable(f_rkusb->out_ep);
usb_ep_disable(f_rkusb->in_ep);
if (f_rkusb->out_req) {
free(f_rkusb->out_req->buf);
usb_ep_free_request(f_rkusb->out_ep,
f_rkusb->out_req);
f_rkusb->out_req = NULL;
}
if (f_rkusb->in_req) {
free(f_rkusb->in_req->buf);
usb_ep_free_request(f_rkusb->in_ep,
f_rkusb->in_req);
f_rkusb->in_req = NULL;
}
+}
+static struct usb_request *rockusb_start_ep(struct usb_ep *ep) +{
struct usb_request *req;
req = usb_ep_alloc_request(ep, 0);
if (!req)
return NULL;
req->length = EP_BUFFER_SIZE;
req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
EP_BUFFER_SIZE);
if (!req->buf) {
usb_ep_free_request(ep, req);
return NULL;
}
memset(req->buf, 0, req->length);
return req;
+}
+static int rockusb_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
+{
int ret;
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct f_rockusb *f_rkusb = func_to_rockusb(f);
const struct usb_endpoint_descriptor *d;
debug("%s: func: %s intf: %d alt: %d\n",
__func__, f->name, interface, alt);
d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
ret = usb_ep_enable(f_rkusb->out_ep, d);
if (ret) {
puts("failed to enable out ep\n");
return ret;
}
f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep);
if (!f_rkusb->out_req) {
puts("failed to alloc out req\n");
ret = -EINVAL;
goto err;
}
f_rkusb->out_req->complete = rx_handler_command;
d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
ret = usb_ep_enable(f_rkusb->in_ep, d);
if (ret) {
puts("failed to enable in ep\n");
goto err;
}
f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep);
if (!f_rkusb->in_req) {
puts("failed alloc req in\n");
ret = -EINVAL;
goto err;
}
f_rkusb->in_req->complete = rockusb_complete;
ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0);
if (ret)
goto err;
return 0;
+err:
rockusb_disable(f);
return ret;
+}
+static int rockusb_add(struct usb_configuration *c) +{
struct f_rockusb *f_rkusb = rockusb_func;
int status;
debug("%s: cdev: 0x%p\n", __func__, c->cdev);
if (!f_rkusb) {
f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE,
sizeof(*f_rkusb));
if (!f_rkusb)
return -ENOMEM;
rockusb_func = f_rkusb;
memset(f_rkusb, 0, sizeof(*f_rkusb));
}
f_rkusb->usb_function.name = "f_rockusb";
f_rkusb->usb_function.bind = rockusb_bind;
f_rkusb->usb_function.unbind = rockusb_unbind;
f_rkusb->usb_function.set_alt = rockusb_set_alt;
f_rkusb->usb_function.disable = rockusb_disable;
f_rkusb->usb_function.strings = rkusb_strings;
status = usb_add_function(c, &f_rkusb->usb_function);
if (status) {
free(f_rkusb);
rockusb_func = f_rkusb;
}
return status;
+}
+char *rockusb_dev_type = 0; +int rockusb_dev_index = 0;
+void rockusb_dev_init(char *dev_type, int dev_index) +{
rockusb_dev_type = dev_type;
rockusb_dev_index = dev_index;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add);
+static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) +{
struct usb_request *in_req = rockusb_func->in_req;
int ret;
memcpy(in_req->buf, buffer, buffer_size);
in_req->length = buffer_size;
usb_ep_dequeue(rockusb_func->in_ep, in_req);
ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0);
if (ret)
printf("Error %d on queue\n", ret);
return 0;
+}
+static int rockusb_tx_write_str(const char *buffer) +{
return rockusb_tx_write(buffer, strlen(buffer));
+}
+/* Bulk-only data structures */
+/* Command Block Wrapper */ +struct fsg_bulk_cb_wrap {
__le32 Signature; /* Contains 'USBC' */
u32 Tag; /* Unique per command id */
__le32 DataTransferLength; /* Size of the data */
u8 Flags; /* Direction in bit 7 */
u8 Lun; /* LUN (normally 0) */
u8 Length; /* Of the CDB, <=
MAX_COMMAND_SIZE */
u8 CDB[16]; /* Command Data Block */
+};
+#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80
+/* Command Status Wrapper */ +struct bulk_cs_wrap {
__le32 Signature; /* Should = 'USBS' */
u32 Tag; /* Same as original
command */
__le32 Residue; /* Amount not transferred
*/
u8 Status; /* See below */
+};
+#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2
+#define CSW_GOOD 0x00 +#define CSW_FAIL 0x01
+static void printcbw(char *buf) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, buf, USB_BULK_CB_WRAP_LEN);
debug("cbw: Signature:%x\n", cbw.Signature);
debug("cbw: Tag=%x\n", cbw.Tag);
debug("cbw: DataTransferLength=%d\n",
cbw.DataTransferLength);
debug("cbw: Flags=%x\n", cbw.Flags);
debug("cbw: Lun=%d\n", cbw.Lun);
debug("cbw: Length=%d\n", cbw.Length);
debug("cbw: ucOperCode=%x\n", cbw.CDB[0]);
debug("cbw: ucReserved=%x\n", cbw.CDB[1]);
debug("cbw: dwAddress:%x %x %x %x\n", cbw.CDB[5],
cbw.CDB[4],
cbw.CDB[3],
cbw.CDB[2]);
debug("cbw: ucReserved2=%x\n", cbw.CDB[6]);
debug("cbw: usLength:%x %x\n", cbw.CDB[8], cbw.CDB[7]);
+}
+static void printcsw(char *buf) +{
struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&csw, buf, USB_BULK_CS_WRAP_LEN);
debug("csw: Signature:%x\n", csw.Signature);
debug("csw: Tag:%x\n", csw.Tag);
debug("csw: Residue:%x\n", csw.Residue);
debug("csw: Status:%x\n", csw.Status);
+}
+static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size) +{
struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
csw.Signature = cpu_to_le32(USB_BULK_CS_SIG);
csw.Tag = Tag;
csw.Residue = cpu_to_be32(residue);
csw.Status = Status;
printcsw((char*)&csw);
return rockusb_tx_write((char*)&csw, size);
+}
+int download_tag = 0; +int download_lba = 0; +static unsigned int download_size; +static unsigned int download_bytes; +struct blk_desc *download_desc = 0;
+static unsigned int rx_bytes_expected(struct usb_ep *ep) +{
int rx_remain = download_size - download_bytes;
unsigned int rem;
unsigned int maxpacket = ep->maxpacket;
if (rx_remain <= 0)
return 0;
else if (rx_remain > EP_BUFFER_SIZE)
return EP_BUFFER_SIZE;
rem = rx_remain % maxpacket;
if (rem > 0)
rx_remain = rx_remain + (maxpacket - rem);
return rx_remain;
+}
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) +{
unsigned int transfer_size = download_size -
download_bytes;
const unsigned char *buffer = req->buf;
unsigned int buffer_size = req->actual;
if(!download_desc){
printf("rx_handler_dl_image blk_get_dev\n");
download_desc = blk_get_dev(rockusb_dev_type,
rockusb_dev_index);
if (!download_desc || download_desc->type ==
DEV_TYPE_UNKNOWN){
error("invalid mmc device\n");
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
}
if (req->status != 0) {
printf("Bad status: %d\n", req->status);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
if (buffer_size < transfer_size)
transfer_size = buffer_size;
memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
buffer, transfer_size);
download_bytes += transfer_size;
/* Check if transfer is done */
if (download_bytes >= download_size) {
int blks = 0, blkcnt = download_size/512;
printf("download %d bytes finished, start writing
to lba %x\n",
download_bytes, download_lba);
blks = blk_dwrite(download_desc, download_lba,
blkcnt,
(char*)CONFIG_FASTBOOT_BUF_ADDR);
if (blks != blkcnt) {
error("failed writing to device %s: %d\n",
rockusb_dev_type,
rockusb_dev_index);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
req->complete = rx_handler_command;
req->length = EP_BUFFER_SIZE;
download_size = 0;
printf("done\n");
rockusb_tx_write_csw(download_tag, 0, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
} else {
req->length = rx_bytes_expected(ep);
}
req->actual = 0;
usb_ep_queue(ep, req, 0);
+}
+static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD, USB_BULK_CS_WRAP_LEN);
+}
+static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
char emmc_id[] = "EMMC ";
printf("cb_read_storage_id\n");
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
rockusb_tx_write_str(emmc_id);//only support emmc now
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
int sector_count;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
sector_count = (int)get_unaligned_be16(&cbw.CDB[7]);
download_lba = get_unaligned_be32(&cbw.CDB[2]);
download_size = sector_count * 512;
download_bytes = 0;
download_tag = cbw.Tag;
if ((0 == download_size) || (download_size>CONFIG_FASTBOOT
_BUF_SIZE)){
rockusb_tx_write_csw(cbw.Tag,
cbw.DataTransferLength,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
} else {
req->complete = rx_handler_dl_image;
req->length = rx_bytes_expected(ep);
}
+}
+static int reboot_flag;
+int __weak rkusb_set_reboot_flag(int flag) +{
printf("rkusb_set_reboot_flag: %d\n", reboot_flag);
return -ENOSYS;
+}
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) +{
rkusb_set_reboot_flag(reboot_flag);
do_reset(NULL, 0, 0, NULL);
+}
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
reboot_flag = 0;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
reboot_flag = cbw.CDB[1];
rockusb_func->in_req->complete = compl_do_reset;
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_not_support(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
printf("Rockusb command %x not support yet\n", cbw.CDB[0]);
rockusb_tx_write_csw(cbw.Tag, 0, CSW_FAIL,
USB_BULK_CS_WRAP_LEN); +}
+#define RKUSB_STATUS_IDLE 0 +#define RKUSB_STATUS_CMD 1 +#define RKUSB_STATUS_RXDATA 2 +#define RKUSB_STATUS_TXDATA 3 +#define RKUSB_STATUS_CSW 4 +#define RKUSB_STATUS_RXDATA_PREPARE 5 +#define RKUSB_STATUS_TXDATA_PREPARE 6
+typedef enum {
TEST_UNIT_READY = 0,
READ_FLASH_ID = 0x01,
TEST_BAD_BLOCK = 0x03,
READ_SECTOR = 0x04,
WRITE_SECTOR = 0x05,
ERASE_NORMAL = 0x06,
ERASE_FORCE = 0x0B,
READ_LBA = 0x14,
WRITE_LBA = 0x15,
ERASE_SYSTEMDISK = 0x16,
READ_SDRAM = 0x17,
WRITE_SDRAM = 0x18,
EXECUTE_SDRAM = 0x19,
READ_FLASH_INFO = 0x1A,
READ_CHIP_INFO = 0x1B,
SET_RESET_FLAG = 0x1E,
WRITE_EFUSE = 0x1F,
READ_EFUSE = 0x20,
READ_SPI_FLASH = 0x21,
WRITE_SPI_FLASH = 0x22,
WRITE_NEW_EFUSE = 0x23,
READ_NEW_EFUSE = 0x24,
DEVICE_RESET = 0xFF
+} USB_OPERATION_CODE;
+#define K_FW_TEST_UNIT_READY 0x00 +#define K_FW_READ_FLASH_ID 0x01 +#define K_FW_SET_DEVICE_ID 0x02 +#define K_FW_TEST_BAD_BLOCK 0x03 +#define K_FW_READ_10 0x04 +#define K_FW_WRITE_10 0x05 +#define K_FW_ERASE_10 0x06 +#define K_FW_WRITE_SPARE 0x07 +#define K_FW_READ_SPARE 0x08
+#define K_FW_ERASE_10_FORCE 0x0b +#define K_FW_GET_VERSION 0x0c
+#define K_FW_LBA_READ_10 0x14 +#define K_FW_LBA_WRITE_10 0x15 +#define K_FW_ERASE_SYS_DISK 0x16 +#define K_FW_SDRAM_READ_10 0x17 +#define K_FW_SDRAM_WRITE_10 0x18 +#define K_FW_SDRAM_EXECUTE 0x19 +#define K_FW_READ_FLASH_INFO 0x1A +#define K_FW_GET_CHIP_VER 0x1B +#define K_FW_LOW_FORMAT 0x1C +#define K_FW_SET_RESET_FLAG 0x1E +#define K_FW_SPI_READ_10 0x21 +#define K_FW_SPI_WRITE_10 0x22
+#define K_FW_SESSION 0X30 +#define K_FW_RESET 0xff
+#define CBW_DIRECTION_OUT 0x00 +#define CBW_DIRECTION_IN 0x80
+struct cmd_dispatch_info {
int cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
{
.cmd = K_FW_TEST_UNIT_READY,
.cb = cb_test_unit_ready,
},
{
.cmd = K_FW_READ_FLASH_ID,
.cb = cb_read_storage_id,
},
{
.cmd = K_FW_SET_DEVICE_ID,
.cb = cb_not_support,
},
{
.cmd = K_FW_TEST_BAD_BLOCK,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_ERASE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_WRITE_SPARE,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_SPARE,
.cb = cb_not_support,
},
{
.cmd = K_FW_ERASE_10_FORCE,
.cb = cb_not_support,
},
{
.cmd = K_FW_GET_VERSION,
.cb = cb_not_support,
},
{
.cmd = K_FW_LBA_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_LBA_WRITE_10,
.cb = cb_write_lba,
},
{
.cmd = K_FW_ERASE_SYS_DISK,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_EXECUTE,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_FLASH_INFO,
.cb = cb_not_support,
},
{
.cmd = K_FW_GET_CHIP_VER,
.cb = cb_not_support,
},
{
.cmd = K_FW_LOW_FORMAT,
.cb = cb_not_support,
},
{
.cmd = K_FW_SET_RESET_FLAG,
.cb = cb_not_support,
},
{
.cmd = K_FW_SPI_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SPI_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SESSION,
.cb = cb_not_support,
},
{
.cmd = K_FW_RESET,
.cb = cb_reboot,
},
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) +{
void (*func_cb)(struct usb_ep *ep, struct usb_request
*req) = NULL;
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
int i;
char *cmdbuf = req->buf;
if (req->status != 0 || req->length == 0)
return;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
printcbw(req->buf);
for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
if (cmd_dispatch_info[i].cmd == cbw.CDB[0]) {
func_cb = cmd_dispatch_info[i].cb;
break;
}
}
if (!func_cb) {
error("unknown command: %s", (char*)req->buf);
rockusb_tx_write_str("FAILunknown command");
} else {
if (req->actual < req->length) {
u8 *buf = (u8 *)req->buf;
buf[req->actual] = 0;
func_cb(ep, req);
} else {
error("buffer overflow");
rockusb_tx_write_str("FAILbuffer
overflow");
}
}
*cmdbuf = '\0';
req->actual = 0;
usb_ep_queue(ep, req, 0);
+}
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

Hi Lukasz
This is my V1 patch. let me know if you have some comment.
2017-03-20 16:37 GMT+08:00 Lukasz Majewski lukma@denx.de:
Hi Eddie,
2017-03-16 15:05 GMT+08:00 Kever Yang kever.yang@rock-chips.com:
Hi Eddie,
I recommend you to use ums framework instead of fastboot,
because ums have dual-buffer which improve performance.
I will try to add dual buffer support in next version
If of course possible - please reuse as much code as possible.
Thanks,
- Kever
On 03/15/2017 03:56 PM, Eddie Cai wrote:
this patch implement fastboot protocol on the device side. this is based on USB download gadget infrastructure. the rockusb function implements the rd, wl, rid commands. it can work with rkdeveloptool; https://github.com/rockchip-linux/rkdeveloptool
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++ +++++++++++ 2 files changed, 802 insertions(+) create mode 100644 drivers/usb/gadget/f_rockusb.c
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 0fbbb7c..0eb27a3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c new file mode 100644 index 0000000..a67cb35 --- /dev/null +++ b/drivers/usb/gadget/f_rockusb.c @@ -0,0 +1,801 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <config.h> +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> +#include <linux/compiler.h> +#include <version.h> +#include <g_dnl.h>
+#define ROCKUSB_VERSION "0.1"
+#define ROCKUSB_INTERFACE_CLASS 0xff +#define ROCKUSB_INTERFACE_SUB_CLASS 0x06 +#define ROCKUSB_INTERFACE_PROTOCOL 0x05
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200) +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040) +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+#define EP_BUFFER_SIZE 4096 +/*
- EP_BUFFER_SIZE must always be an integral multiple of
maxpacket size
- (64 or 512 or 1024), else we break on certain controllers like
DWC3
- that expect bulk OUT requests to be divisible by maxpacket
size.
- */
+struct f_rockusb {
struct usb_function usb_function;
/* IN/OUT EP's and corresponding requests */
struct usb_ep *in_ep, *out_ep;
struct usb_request *in_req, *out_req;
+};
+static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) +{
return container_of(f, struct f_rockusb, usb_function);
+}
+static struct f_rockusb *rockusb_func;
+static struct usb_endpoint_descriptor fs_ep_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor fs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor hs_ep_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_endpoint_descriptor hs_ep_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_interface_descriptor interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = ROCKUSB_INTERFACE_CLASS,
.bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS,
.bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL,
+};
+static struct usb_descriptor_header *rkusb_fs_function[] = {
(struct usb_descriptor_header *)&interface_desc,
(struct usb_descriptor_header *)&fs_ep_in,
(struct usb_descriptor_header *)&fs_ep_out,
+};
+static struct usb_descriptor_header *rkusb_hs_function[] = {
(struct usb_descriptor_header *)&interface_desc,
(struct usb_descriptor_header *)&hs_ep_in,
(struct usb_descriptor_header *)&hs_ep_out,
NULL,
+};
+static struct usb_endpoint_descriptor * +rkusb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
+{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
+}
+/*
- static strings, in UTF-8
- */
+static const char rkusb_name[] = "Rockchip Rockusb";
+static struct usb_string rkusb_string_defs[] = {
[0].s = rkusb_name,
{ } /* end of list */
+};
+static struct usb_gadget_strings stringtab_rkusb = {
.language = 0x0409, /* en-us */
.strings = rkusb_string_defs,
+};
+static struct usb_gadget_strings *rkusb_strings[] = {
&stringtab_rkusb,
NULL,
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); +static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size);
+static void rockusb_complete(struct usb_ep *ep, struct usb_request *req) +{
int status = req->status;
if (!status)
return;
debug("status: %d ep '%s' trans: %d\n", status, ep->name,
req->actual); +}
+static int rockusb_bind(struct usb_configuration *c, struct usb_function *f) +{
int id;
struct usb_gadget *gadget = c->cdev->gadget;
struct f_rockusb *f_rkusb = func_to_rockusb(f);
const char *s;
id = usb_interface_id(c, f);
if (id < 0)
return id;
interface_desc.bInterfaceNumber = id;
id = usb_string_id(c->cdev);
if (id < 0)
return id;
rkusb_string_defs[0].id = id;
interface_desc.iInterface = id;
f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
if (!f_rkusb->in_ep)
return -ENODEV;
f_rkusb->in_ep->driver_data = c->cdev;
f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
if (!f_rkusb->out_ep)
return -ENODEV;
f_rkusb->out_ep->driver_data = c->cdev;
f->descriptors = rkusb_fs_function;
if (gadget_is_dualspeed(gadget)) {
hs_ep_in.bEndpointAddress =
fs_ep_in.bEndpointAddress;
hs_ep_out.bEndpointAddress =
fs_ep_out.bEndpointAddress;
f->hs_descriptors = rkusb_hs_function;
}
s = getenv("serial#");
if (s)
g_dnl_set_serialnumber((char *)s);
return 0;
+}
+static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f) +{
memset(rockusb_func, 0, sizeof(*rockusb_func));
+}
+static void rockusb_disable(struct usb_function *f) +{
struct f_rockusb *f_rkusb = func_to_rockusb(f);
usb_ep_disable(f_rkusb->out_ep);
usb_ep_disable(f_rkusb->in_ep);
if (f_rkusb->out_req) {
free(f_rkusb->out_req->buf);
usb_ep_free_request(f_rkusb->out_ep,
f_rkusb->out_req);
f_rkusb->out_req = NULL;
}
if (f_rkusb->in_req) {
free(f_rkusb->in_req->buf);
usb_ep_free_request(f_rkusb->in_ep,
f_rkusb->in_req);
f_rkusb->in_req = NULL;
}
+}
+static struct usb_request *rockusb_start_ep(struct usb_ep *ep) +{
struct usb_request *req;
req = usb_ep_alloc_request(ep, 0);
if (!req)
return NULL;
req->length = EP_BUFFER_SIZE;
req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
EP_BUFFER_SIZE);
if (!req->buf) {
usb_ep_free_request(ep, req);
return NULL;
}
memset(req->buf, 0, req->length);
return req;
+}
+static int rockusb_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
+{
int ret;
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct f_rockusb *f_rkusb = func_to_rockusb(f);
const struct usb_endpoint_descriptor *d;
debug("%s: func: %s intf: %d alt: %d\n",
__func__, f->name, interface, alt);
d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
ret = usb_ep_enable(f_rkusb->out_ep, d);
if (ret) {
puts("failed to enable out ep\n");
return ret;
}
f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep);
if (!f_rkusb->out_req) {
puts("failed to alloc out req\n");
ret = -EINVAL;
goto err;
}
f_rkusb->out_req->complete = rx_handler_command;
d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
ret = usb_ep_enable(f_rkusb->in_ep, d);
if (ret) {
puts("failed to enable in ep\n");
goto err;
}
f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep);
if (!f_rkusb->in_req) {
puts("failed alloc req in\n");
ret = -EINVAL;
goto err;
}
f_rkusb->in_req->complete = rockusb_complete;
ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0);
if (ret)
goto err;
return 0;
+err:
rockusb_disable(f);
return ret;
+}
+static int rockusb_add(struct usb_configuration *c) +{
struct f_rockusb *f_rkusb = rockusb_func;
int status;
debug("%s: cdev: 0x%p\n", __func__, c->cdev);
if (!f_rkusb) {
f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE,
sizeof(*f_rkusb));
if (!f_rkusb)
return -ENOMEM;
rockusb_func = f_rkusb;
memset(f_rkusb, 0, sizeof(*f_rkusb));
}
f_rkusb->usb_function.name = "f_rockusb";
f_rkusb->usb_function.bind = rockusb_bind;
f_rkusb->usb_function.unbind = rockusb_unbind;
f_rkusb->usb_function.set_alt = rockusb_set_alt;
f_rkusb->usb_function.disable = rockusb_disable;
f_rkusb->usb_function.strings = rkusb_strings;
status = usb_add_function(c, &f_rkusb->usb_function);
if (status) {
free(f_rkusb);
rockusb_func = f_rkusb;
}
return status;
+}
+char *rockusb_dev_type = 0; +int rockusb_dev_index = 0;
+void rockusb_dev_init(char *dev_type, int dev_index) +{
rockusb_dev_type = dev_type;
rockusb_dev_index = dev_index;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add);
+static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) +{
struct usb_request *in_req = rockusb_func->in_req;
int ret;
memcpy(in_req->buf, buffer, buffer_size);
in_req->length = buffer_size;
usb_ep_dequeue(rockusb_func->in_ep, in_req);
ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0);
if (ret)
printf("Error %d on queue\n", ret);
return 0;
+}
+static int rockusb_tx_write_str(const char *buffer) +{
return rockusb_tx_write(buffer, strlen(buffer));
+}
+/* Bulk-only data structures */
+/* Command Block Wrapper */ +struct fsg_bulk_cb_wrap {
__le32 Signature; /* Contains 'USBC' */
u32 Tag; /* Unique per command id */
__le32 DataTransferLength; /* Size of the data */
u8 Flags; /* Direction in bit 7 */
u8 Lun; /* LUN (normally 0) */
u8 Length; /* Of the CDB, <=
MAX_COMMAND_SIZE */
u8 CDB[16]; /* Command Data Block */
+};
+#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80
+/* Command Status Wrapper */ +struct bulk_cs_wrap {
__le32 Signature; /* Should = 'USBS' */
u32 Tag; /* Same as original
command */
__le32 Residue; /* Amount not transferred
*/
u8 Status; /* See below */
+};
+#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2
+#define CSW_GOOD 0x00 +#define CSW_FAIL 0x01
+static void printcbw(char *buf) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, buf, USB_BULK_CB_WRAP_LEN);
debug("cbw: Signature:%x\n", cbw.Signature);
debug("cbw: Tag=%x\n", cbw.Tag);
debug("cbw: DataTransferLength=%d\n",
cbw.DataTransferLength);
debug("cbw: Flags=%x\n", cbw.Flags);
debug("cbw: Lun=%d\n", cbw.Lun);
debug("cbw: Length=%d\n", cbw.Length);
debug("cbw: ucOperCode=%x\n", cbw.CDB[0]);
debug("cbw: ucReserved=%x\n", cbw.CDB[1]);
debug("cbw: dwAddress:%x %x %x %x\n", cbw.CDB[5],
cbw.CDB[4],
cbw.CDB[3],
cbw.CDB[2]);
debug("cbw: ucReserved2=%x\n", cbw.CDB[6]);
debug("cbw: usLength:%x %x\n", cbw.CDB[8], cbw.CDB[7]);
+}
+static void printcsw(char *buf) +{
struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&csw, buf, USB_BULK_CS_WRAP_LEN);
debug("csw: Signature:%x\n", csw.Signature);
debug("csw: Tag:%x\n", csw.Tag);
debug("csw: Residue:%x\n", csw.Residue);
debug("csw: Status:%x\n", csw.Status);
+}
+static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size) +{
struct bulk_cs_wrap csw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
csw.Signature = cpu_to_le32(USB_BULK_CS_SIG);
csw.Tag = Tag;
csw.Residue = cpu_to_be32(residue);
csw.Status = Status;
printcsw((char*)&csw);
return rockusb_tx_write((char*)&csw, size);
+}
+int download_tag = 0; +int download_lba = 0; +static unsigned int download_size; +static unsigned int download_bytes; +struct blk_desc *download_desc = 0;
+static unsigned int rx_bytes_expected(struct usb_ep *ep) +{
int rx_remain = download_size - download_bytes;
unsigned int rem;
unsigned int maxpacket = ep->maxpacket;
if (rx_remain <= 0)
return 0;
else if (rx_remain > EP_BUFFER_SIZE)
return EP_BUFFER_SIZE;
rem = rx_remain % maxpacket;
if (rem > 0)
rx_remain = rx_remain + (maxpacket - rem);
return rx_remain;
+}
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) +{
unsigned int transfer_size = download_size -
download_bytes;
const unsigned char *buffer = req->buf;
unsigned int buffer_size = req->actual;
if(!download_desc){
printf("rx_handler_dl_image blk_get_dev\n");
download_desc = blk_get_dev(rockusb_dev_type,
rockusb_dev_index);
if (!download_desc || download_desc->type ==
DEV_TYPE_UNKNOWN){
error("invalid mmc device\n");
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
}
if (req->status != 0) {
printf("Bad status: %d\n", req->status);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
if (buffer_size < transfer_size)
transfer_size = buffer_size;
memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
buffer, transfer_size);
download_bytes += transfer_size;
/* Check if transfer is done */
if (download_bytes >= download_size) {
int blks = 0, blkcnt = download_size/512;
printf("download %d bytes finished, start writing
to lba %x\n",
download_bytes, download_lba);
blks = blk_dwrite(download_desc, download_lba,
blkcnt,
(char*)CONFIG_FASTBOOT_BUF_ADDR);
if (blks != blkcnt) {
error("failed writing to device %s: %d\n",
rockusb_dev_type,
rockusb_dev_index);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
req->complete = rx_handler_command;
req->length = EP_BUFFER_SIZE;
download_size = 0;
printf("done\n");
rockusb_tx_write_csw(download_tag, 0, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
} else {
req->length = rx_bytes_expected(ep);
}
req->actual = 0;
usb_ep_queue(ep, req, 0);
+}
+static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD, USB_BULK_CS_WRAP_LEN);
+}
+static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
char emmc_id[] = "EMMC ";
printf("cb_read_storage_id\n");
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
rockusb_tx_write_str(emmc_id);//only support emmc now
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
int sector_count;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
sector_count = (int)get_unaligned_be16(&cbw.CDB[7]);
download_lba = get_unaligned_be32(&cbw.CDB[2]);
download_size = sector_count * 512;
download_bytes = 0;
download_tag = cbw.Tag;
if ((0 == download_size) || (download_size>CONFIG_FASTBOOT
_BUF_SIZE)){
rockusb_tx_write_csw(cbw.Tag,
cbw.DataTransferLength,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
} else {
req->complete = rx_handler_dl_image;
req->length = rx_bytes_expected(ep);
}
+}
+static int reboot_flag;
+int __weak rkusb_set_reboot_flag(int flag) +{
printf("rkusb_set_reboot_flag: %d\n", reboot_flag);
return -ENOSYS;
+}
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) +{
rkusb_set_reboot_flag(reboot_flag);
do_reset(NULL, 0, 0, NULL);
+}
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
reboot_flag = 0;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
reboot_flag = cbw.CDB[1];
rockusb_func->in_req->complete = compl_do_reset;
rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_not_support(struct usb_ep *ep, struct usb_request *req) +{
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
printf("Rockusb command %x not support yet\n", cbw.CDB[0]);
rockusb_tx_write_csw(cbw.Tag, 0, CSW_FAIL,
USB_BULK_CS_WRAP_LEN); +}
+#define RKUSB_STATUS_IDLE 0 +#define RKUSB_STATUS_CMD 1 +#define RKUSB_STATUS_RXDATA 2 +#define RKUSB_STATUS_TXDATA 3 +#define RKUSB_STATUS_CSW 4 +#define RKUSB_STATUS_RXDATA_PREPARE 5 +#define RKUSB_STATUS_TXDATA_PREPARE 6
+typedef enum {
TEST_UNIT_READY = 0,
READ_FLASH_ID = 0x01,
TEST_BAD_BLOCK = 0x03,
READ_SECTOR = 0x04,
WRITE_SECTOR = 0x05,
ERASE_NORMAL = 0x06,
ERASE_FORCE = 0x0B,
READ_LBA = 0x14,
WRITE_LBA = 0x15,
ERASE_SYSTEMDISK = 0x16,
READ_SDRAM = 0x17,
WRITE_SDRAM = 0x18,
EXECUTE_SDRAM = 0x19,
READ_FLASH_INFO = 0x1A,
READ_CHIP_INFO = 0x1B,
SET_RESET_FLAG = 0x1E,
WRITE_EFUSE = 0x1F,
READ_EFUSE = 0x20,
READ_SPI_FLASH = 0x21,
WRITE_SPI_FLASH = 0x22,
WRITE_NEW_EFUSE = 0x23,
READ_NEW_EFUSE = 0x24,
DEVICE_RESET = 0xFF
+} USB_OPERATION_CODE;
+#define K_FW_TEST_UNIT_READY 0x00 +#define K_FW_READ_FLASH_ID 0x01 +#define K_FW_SET_DEVICE_ID 0x02 +#define K_FW_TEST_BAD_BLOCK 0x03 +#define K_FW_READ_10 0x04 +#define K_FW_WRITE_10 0x05 +#define K_FW_ERASE_10 0x06 +#define K_FW_WRITE_SPARE 0x07 +#define K_FW_READ_SPARE 0x08
+#define K_FW_ERASE_10_FORCE 0x0b +#define K_FW_GET_VERSION 0x0c
+#define K_FW_LBA_READ_10 0x14 +#define K_FW_LBA_WRITE_10 0x15 +#define K_FW_ERASE_SYS_DISK 0x16 +#define K_FW_SDRAM_READ_10 0x17 +#define K_FW_SDRAM_WRITE_10 0x18 +#define K_FW_SDRAM_EXECUTE 0x19 +#define K_FW_READ_FLASH_INFO 0x1A +#define K_FW_GET_CHIP_VER 0x1B +#define K_FW_LOW_FORMAT 0x1C +#define K_FW_SET_RESET_FLAG 0x1E +#define K_FW_SPI_READ_10 0x21 +#define K_FW_SPI_WRITE_10 0x22
+#define K_FW_SESSION 0X30 +#define K_FW_RESET 0xff
+#define CBW_DIRECTION_OUT 0x00 +#define CBW_DIRECTION_IN 0x80
+struct cmd_dispatch_info {
int cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
{
.cmd = K_FW_TEST_UNIT_READY,
.cb = cb_test_unit_ready,
},
{
.cmd = K_FW_READ_FLASH_ID,
.cb = cb_read_storage_id,
},
{
.cmd = K_FW_SET_DEVICE_ID,
.cb = cb_not_support,
},
{
.cmd = K_FW_TEST_BAD_BLOCK,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_ERASE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_WRITE_SPARE,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_SPARE,
.cb = cb_not_support,
},
{
.cmd = K_FW_ERASE_10_FORCE,
.cb = cb_not_support,
},
{
.cmd = K_FW_GET_VERSION,
.cb = cb_not_support,
},
{
.cmd = K_FW_LBA_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_LBA_WRITE_10,
.cb = cb_write_lba,
},
{
.cmd = K_FW_ERASE_SYS_DISK,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SDRAM_EXECUTE,
.cb = cb_not_support,
},
{
.cmd = K_FW_READ_FLASH_INFO,
.cb = cb_not_support,
},
{
.cmd = K_FW_GET_CHIP_VER,
.cb = cb_not_support,
},
{
.cmd = K_FW_LOW_FORMAT,
.cb = cb_not_support,
},
{
.cmd = K_FW_SET_RESET_FLAG,
.cb = cb_not_support,
},
{
.cmd = K_FW_SPI_READ_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SPI_WRITE_10,
.cb = cb_not_support,
},
{
.cmd = K_FW_SESSION,
.cb = cb_not_support,
},
{
.cmd = K_FW_RESET,
.cb = cb_reboot,
},
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) +{
void (*func_cb)(struct usb_ep *ep, struct usb_request
*req) = NULL;
struct fsg_bulk_cb_wrap cbw __attribute__((aligned(ARCH_DM
A_MINALIGN)));
int i;
char *cmdbuf = req->buf;
if (req->status != 0 || req->length == 0)
return;
memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
printcbw(req->buf);
for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
if (cmd_dispatch_info[i].cmd == cbw.CDB[0]) {
func_cb = cmd_dispatch_info[i].cb;
break;
}
}
if (!func_cb) {
error("unknown command: %s", (char*)req->buf);
rockusb_tx_write_str("FAILunknown command");
} else {
if (req->actual < req->length) {
u8 *buf = (u8 *)req->buf;
buf[req->actual] = 0;
func_cb(ep, req);
} else {
error("buffer overflow");
rockusb_tx_write_str("FAILbuffer
overflow");
}
}
*cmdbuf = '\0';
req->actual = 0;
usb_ep_queue(ep, req, 0);
+}
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

Hi Eddie,
this patch implement fastboot protocol on the device side. this is based on USB download gadget infrastructure. the rockusb function implements the rd, wl, rid commands. it can work with rkdeveloptool; https://github.com/rockchip-linux/rkdeveloptool
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 802 insertions(+) create mode 100644 drivers/usb/gadget/f_rockusb.c
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 0fbbb7c..0eb27a3 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_rockusb.c b/drivers/usb/gadget/f_rockusb.c new file mode 100644 index 0000000..a67cb35 --- /dev/null +++ b/drivers/usb/gadget/f_rockusb.c @@ -0,0 +1,801 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <config.h> +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/composite.h> +#include <linux/compiler.h> +#include <version.h> +#include <g_dnl.h>
+#define ROCKUSB_VERSION "0.1"
+#define ROCKUSB_INTERFACE_CLASS 0xff +#define ROCKUSB_INTERFACE_SUB_CLASS 0x06 +#define ROCKUSB_INTERFACE_PROTOCOL 0x05
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200) +#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040) +#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+#define EP_BUFFER_SIZE 4096 +/*
- EP_BUFFER_SIZE must always be an integral multiple of maxpacket
size
- (64 or 512 or 1024), else we break on certain controllers like
DWC3
- that expect bulk OUT requests to be divisible by maxpacket size.
- */
Maybe you could put those defines to f_rockchip.h file (which would be local to the f_rockchip.c)?
It could store defines and structs local to the rockchip protocol.
+struct f_rockusb {
- struct usb_function usb_function;
- /* IN/OUT EP's and corresponding requests */
- struct usb_ep *in_ep, *out_ep;
- struct usb_request *in_req, *out_req;
+};
+static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) +{
- return container_of(f, struct f_rockusb, usb_function);
+}
+static struct f_rockusb *rockusb_func;
+static struct usb_endpoint_descriptor fs_ep_in = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor fs_ep_out = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(64),
+};
+static struct usb_endpoint_descriptor hs_ep_in = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_endpoint_descriptor hs_ep_out = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
+};
+static struct usb_interface_descriptor interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0x00,
- .bAlternateSetting = 0x00,
- .bNumEndpoints = 0x02,
- .bInterfaceClass = ROCKUSB_INTERFACE_CLASS,
- .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS,
- .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL,
+};
+static struct usb_descriptor_header *rkusb_fs_function[] = {
- (struct usb_descriptor_header *)&interface_desc,
- (struct usb_descriptor_header *)&fs_ep_in,
- (struct usb_descriptor_header *)&fs_ep_out,
+};
+static struct usb_descriptor_header *rkusb_hs_function[] = {
- (struct usb_descriptor_header *)&interface_desc,
- (struct usb_descriptor_header *)&hs_ep_in,
- (struct usb_descriptor_header *)&hs_ep_out,
- NULL,
+};
+static struct usb_endpoint_descriptor * +rkusb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
+{
- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
- return fs;
+}
+/*
- static strings, in UTF-8
- */
+static const char rkusb_name[] = "Rockchip Rockusb";
+static struct usb_string rkusb_string_defs[] = {
- [0].s = rkusb_name,
- { } /* end of list */
+};
+static struct usb_gadget_strings stringtab_rkusb = {
- .language = 0x0409, /* en-us */
- .strings = rkusb_string_defs,
+};
+static struct usb_gadget_strings *rkusb_strings[] = {
- &stringtab_rkusb,
- NULL,
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); +static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size); + +static void rockusb_complete(struct usb_ep *ep, struct usb_request *req) +{
- int status = req->status;
- if (!status)
return;
- debug("status: %d ep '%s' trans: %d\n", status, ep->name,
req->actual); +}
+static int rockusb_bind(struct usb_configuration *c, struct usb_function *f) +{
- int id;
- struct usb_gadget *gadget = c->cdev->gadget;
- struct f_rockusb *f_rkusb = func_to_rockusb(f);
- const char *s;
- id = usb_interface_id(c, f);
- if (id < 0)
return id;
- interface_desc.bInterfaceNumber = id;
- id = usb_string_id(c->cdev);
- if (id < 0)
return id;
- rkusb_string_defs[0].id = id;
- interface_desc.iInterface = id;
- f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
- if (!f_rkusb->in_ep)
return -ENODEV;
- f_rkusb->in_ep->driver_data = c->cdev;
- f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
- if (!f_rkusb->out_ep)
return -ENODEV;
- f_rkusb->out_ep->driver_data = c->cdev;
- f->descriptors = rkusb_fs_function;
- if (gadget_is_dualspeed(gadget)) {
hs_ep_in.bEndpointAddress =
fs_ep_in.bEndpointAddress;
hs_ep_out.bEndpointAddress =
fs_ep_out.bEndpointAddress;
f->hs_descriptors = rkusb_hs_function;
- }
- s = getenv("serial#");
- if (s)
g_dnl_set_serialnumber((char *)s);
- return 0;
+}
+static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f) +{
- memset(rockusb_func, 0, sizeof(*rockusb_func));
+}
+static void rockusb_disable(struct usb_function *f) +{
- struct f_rockusb *f_rkusb = func_to_rockusb(f);
- usb_ep_disable(f_rkusb->out_ep);
- usb_ep_disable(f_rkusb->in_ep);
- if (f_rkusb->out_req) {
free(f_rkusb->out_req->buf);
usb_ep_free_request(f_rkusb->out_ep,
f_rkusb->out_req);
f_rkusb->out_req = NULL;
- }
- if (f_rkusb->in_req) {
free(f_rkusb->in_req->buf);
usb_ep_free_request(f_rkusb->in_ep, f_rkusb->in_req);
f_rkusb->in_req = NULL;
- }
+}
+static struct usb_request *rockusb_start_ep(struct usb_ep *ep) +{
- struct usb_request *req;
- req = usb_ep_alloc_request(ep, 0);
- if (!req)
return NULL;
- req->length = EP_BUFFER_SIZE;
- req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
EP_BUFFER_SIZE);
- if (!req->buf) {
usb_ep_free_request(ep, req);
return NULL;
- }
- memset(req->buf, 0, req->length);
- return req;
+}
+static int rockusb_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
+{
- int ret;
- struct usb_composite_dev *cdev = f->config->cdev;
- struct usb_gadget *gadget = cdev->gadget;
- struct f_rockusb *f_rkusb = func_to_rockusb(f);
- const struct usb_endpoint_descriptor *d;
- debug("%s: func: %s intf: %d alt: %d\n",
__func__, f->name, interface, alt);
- d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out);
- ret = usb_ep_enable(f_rkusb->out_ep, d);
- if (ret) {
puts("failed to enable out ep\n");
return ret;
- }
- f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep);
- if (!f_rkusb->out_req) {
puts("failed to alloc out req\n");
ret = -EINVAL;
goto err;
- }
- f_rkusb->out_req->complete = rx_handler_command;
- d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in);
- ret = usb_ep_enable(f_rkusb->in_ep, d);
- if (ret) {
puts("failed to enable in ep\n");
goto err;
- }
- f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep);
- if (!f_rkusb->in_req) {
puts("failed alloc req in\n");
ret = -EINVAL;
goto err;
- }
- f_rkusb->in_req->complete = rockusb_complete;
- ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0);
- if (ret)
goto err;
- return 0;
+err:
- rockusb_disable(f);
- return ret;
+}
+static int rockusb_add(struct usb_configuration *c) +{
- struct f_rockusb *f_rkusb = rockusb_func;
- int status;
- debug("%s: cdev: 0x%p\n", __func__, c->cdev);
- if (!f_rkusb) {
f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE,
sizeof(*f_rkusb));
if (!f_rkusb)
return -ENOMEM;
rockusb_func = f_rkusb;
memset(f_rkusb, 0, sizeof(*f_rkusb));
- }
- f_rkusb->usb_function.name = "f_rockusb";
- f_rkusb->usb_function.bind = rockusb_bind;
- f_rkusb->usb_function.unbind = rockusb_unbind;
- f_rkusb->usb_function.set_alt = rockusb_set_alt;
- f_rkusb->usb_function.disable = rockusb_disable;
- f_rkusb->usb_function.strings = rkusb_strings;
- status = usb_add_function(c, &f_rkusb->usb_function);
- if (status) {
free(f_rkusb);
rockusb_func = f_rkusb;
- }
- return status;
+}
+char *rockusb_dev_type = 0; +int rockusb_dev_index = 0;
+void rockusb_dev_init(char *dev_type, int dev_index) +{
- rockusb_dev_type = dev_type;
- rockusb_dev_index = dev_index;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add);
+static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) +{
- struct usb_request *in_req = rockusb_func->in_req;
- int ret;
- memcpy(in_req->buf, buffer, buffer_size);
- in_req->length = buffer_size;
- usb_ep_dequeue(rockusb_func->in_ep, in_req);
- ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0);
- if (ret)
printf("Error %d on queue\n", ret);
- return 0;
+}
+static int rockusb_tx_write_str(const char *buffer) +{
- return rockusb_tx_write(buffer, strlen(buffer));
+}
+/* Bulk-only data structures */
+/* Command Block Wrapper */ +struct fsg_bulk_cb_wrap {
- __le32 Signature; /* Contains 'USBC' */
- u32 Tag; /* Unique per command
id */
- __le32 DataTransferLength; /* Size of the data
*/
- u8 Flags; /* Direction in bit
7 */
- u8 Lun; /* LUN (normally 0) */
- u8 Length; /* Of the CDB, <=
MAX_COMMAND_SIZE */
- u8 CDB[16]; /* Command Data Block */
+};
+#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80
+/* Command Status Wrapper */ +struct bulk_cs_wrap {
- __le32 Signature; /* Should = 'USBS' */
- u32 Tag; /* Same as original
command */
- __le32 Residue; /* Amount not
transferred */
- u8 Status; /* See below */
+};
+#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2
+#define CSW_GOOD 0x00 +#define CSW_FAIL 0x01
+static void printcbw(char *buf) +{
- struct fsg_bulk_cb_wrap cbw
__attribute__((aligned(ARCH_DMA_MINALIGN))); +
- memcpy((char*)&cbw, buf, USB_BULK_CB_WRAP_LEN);
- debug("cbw: Signature:%x\n", cbw.Signature);
- debug("cbw: Tag=%x\n", cbw.Tag);
- debug("cbw: DataTransferLength=%d\n",
cbw.DataTransferLength);
- debug("cbw: Flags=%x\n", cbw.Flags);
- debug("cbw: Lun=%d\n", cbw.Lun);
- debug("cbw: Length=%d\n", cbw.Length);
- debug("cbw: ucOperCode=%x\n", cbw.CDB[0]);
- debug("cbw: ucReserved=%x\n", cbw.CDB[1]);
- debug("cbw: dwAddress:%x %x %x %x\n", cbw.CDB[5],
cbw.CDB[4],
cbw.CDB[3],
cbw.CDB[2]);
- debug("cbw: ucReserved2=%x\n", cbw.CDB[6]);
- debug("cbw: usLength:%x %x\n", cbw.CDB[8], cbw.CDB[7]);
+}
+static void printcsw(char *buf) +{
- struct bulk_cs_wrap csw
__attribute__((aligned(ARCH_DMA_MINALIGN))); +
- memcpy((char*)&csw, buf, USB_BULK_CS_WRAP_LEN);
- debug("csw: Signature:%x\n", csw.Signature);
- debug("csw: Tag:%x\n", csw.Tag);
- debug("csw: Residue:%x\n", csw.Residue);
- debug("csw: Status:%x\n", csw.Status);
+}
Those debug functions should go to f_rockchip.h file and should be guarded with #ifdef DEBUG
+static int rockusb_tx_write_csw(u32 Tag, int residue, u8 Status, int size) +{
- struct bulk_cs_wrap csw
__attribute__((aligned(ARCH_DMA_MINALIGN)));
- csw.Signature = cpu_to_le32(USB_BULK_CS_SIG);
- csw.Tag = Tag;
- csw.Residue = cpu_to_be32(residue);
- csw.Status = Status;
- printcsw((char*)&csw);
- return rockusb_tx_write((char*)&csw, size);
+}
+int download_tag = 0; +int download_lba = 0; +static unsigned int download_size; +static unsigned int download_bytes; +struct blk_desc *download_desc = 0;
This pointer is allocated in BSS, so should be cleared (NULL'ed).
+static unsigned int rx_bytes_expected(struct usb_ep *ep) +{
- int rx_remain = download_size - download_bytes;
- unsigned int rem;
- unsigned int maxpacket = ep->maxpacket;
- if (rx_remain <= 0)
return 0;
- else if (rx_remain > EP_BUFFER_SIZE)
return EP_BUFFER_SIZE;
- rem = rx_remain % maxpacket;
- if (rem > 0)
rx_remain = rx_remain + (maxpacket - rem);
- return rx_remain;
+}
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) +{
- unsigned int transfer_size = download_size - download_bytes;
- const unsigned char *buffer = req->buf;
- unsigned int buffer_size = req->actual;
- if(!download_desc){
printf("rx_handler_dl_image blk_get_dev\n");
download_desc = blk_get_dev(rockusb_dev_type,
rockusb_dev_index);
if (!download_desc || download_desc->type ==
DEV_TYPE_UNKNOWN){
error("invalid mmc device\n");
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
- }
- if (req->status != 0) {
printf("Bad status: %d\n", req->status);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
- }
- if (buffer_size < transfer_size)
transfer_size = buffer_size;
- memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes,
Here we should have different name for CONFIG_*_BUF_ADDR - e.g. CONFIG_ROCKCHIP_BUF_ADDR, which should be defined in Kconfig as well (with some default value).
buffer, transfer_size);
- download_bytes += transfer_size;
- /* Check if transfer is done */
- if (download_bytes >= download_size) {
int blks = 0, blkcnt = download_size/512;
printf("download %d bytes finished, start writing to
lba %x\n",
download_bytes, download_lba);
blks = blk_dwrite(download_desc, download_lba,
blkcnt,
(char*)CONFIG_FASTBOOT_BUF_ADDR);
if (blks != blkcnt) {
error("failed writing to device %s: %d\n",
rockusb_dev_type, rockusb_dev_index);
rockusb_tx_write_csw(download_tag, 0,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
return;
}
req->complete = rx_handler_command;
req->length = EP_BUFFER_SIZE;
download_size = 0;
printf("done\n");
rockusb_tx_write_csw(download_tag, 0, CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
- } else {
req->length = rx_bytes_expected(ep);
- }
- req->actual = 0;
- usb_ep_queue(ep, req, 0);
+}
+static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw
__attribute__((aligned(ARCH_DMA_MINALIGN))); +
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
You can use ALLOC_CACHE_ALIGN_BUFFER() to define cache safe struct inside the function. Please fix it globally.
For global cache safe allocations you can use DEFINE_CACHE_ALIGN_BUFFER (more info at ./include/memalign.h)
- rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD, USB_BULK_CS_WRAP_LEN);
+}
+static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw
__attribute__((aligned(ARCH_DMA_MINALIGN)));
- char emmc_id[] = "EMMC ";
- printf("cb_read_storage_id\n");
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- rockusb_tx_write_str(emmc_id);//only support emmc now
- rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw
__attribute__((aligned(ARCH_DMA_MINALIGN)));
- int sector_count;
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- sector_count = (int)get_unaligned_be16(&cbw.CDB[7]);
- download_lba = get_unaligned_be32(&cbw.CDB[2]);
- download_size = sector_count * 512;
- download_bytes = 0;
- download_tag = cbw.Tag;
- if ((0 == download_size) ||
(download_size>CONFIG_FASTBOOT_BUF_SIZE)){
rockusb_tx_write_csw(cbw.Tag,
cbw.DataTransferLength,
CSW_FAIL,
USB_BULK_CS_WRAP_LEN);
- } else {
req->complete = rx_handler_dl_image;
req->length = rx_bytes_expected(ep);
- }
+}
+static int reboot_flag;
+int __weak rkusb_set_reboot_flag(int flag) +{
- printf("rkusb_set_reboot_flag: %d\n", reboot_flag);
- return -ENOSYS;
+}
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) +{
- rkusb_set_reboot_flag(reboot_flag);
- do_reset(NULL, 0, 0, NULL);
+}
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw
__attribute__((aligned(ARCH_DMA_MINALIGN)));
- reboot_flag = 0;
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- reboot_flag = cbw.CDB[1];
- rockusb_func->in_req->complete = compl_do_reset;
- rockusb_tx_write_csw(cbw.Tag, cbw.DataTransferLength,
CSW_GOOD,
USB_BULK_CS_WRAP_LEN);
+}
+static void cb_not_support(struct usb_ep *ep, struct usb_request *req) +{
- struct fsg_bulk_cb_wrap cbw
__attribute__((aligned(ARCH_DMA_MINALIGN))); +
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- printf("Rockusb command %x not support yet\n", cbw.CDB[0]);
- rockusb_tx_write_csw(cbw.Tag, 0, CSW_FAIL,
USB_BULK_CS_WRAP_LEN); +}
------------------------>8--------------------------
+#define RKUSB_STATUS_IDLE 0 +#define RKUSB_STATUS_CMD 1 +#define RKUSB_STATUS_RXDATA 2 +#define RKUSB_STATUS_TXDATA 3 +#define RKUSB_STATUS_CSW 4 +#define RKUSB_STATUS_RXDATA_PREPARE 5 +#define RKUSB_STATUS_TXDATA_PREPARE 6
+typedef enum {
TEST_UNIT_READY = 0,
READ_FLASH_ID = 0x01,
TEST_BAD_BLOCK = 0x03,
READ_SECTOR = 0x04,
WRITE_SECTOR = 0x05,
ERASE_NORMAL = 0x06,
ERASE_FORCE = 0x0B,
READ_LBA = 0x14,
WRITE_LBA = 0x15,
ERASE_SYSTEMDISK = 0x16,
READ_SDRAM = 0x17,
WRITE_SDRAM = 0x18,
EXECUTE_SDRAM = 0x19,
READ_FLASH_INFO = 0x1A,
READ_CHIP_INFO = 0x1B,
SET_RESET_FLAG = 0x1E,
WRITE_EFUSE = 0x1F,
READ_EFUSE = 0x20,
READ_SPI_FLASH = 0x21,
WRITE_SPI_FLASH = 0x22,
WRITE_NEW_EFUSE = 0x23,
READ_NEW_EFUSE = 0x24,
DEVICE_RESET = 0xFF
+} USB_OPERATION_CODE;
+#define K_FW_TEST_UNIT_READY 0x00 +#define K_FW_READ_FLASH_ID 0x01 +#define K_FW_SET_DEVICE_ID 0x02 +#define K_FW_TEST_BAD_BLOCK 0x03 +#define K_FW_READ_10 0x04 +#define K_FW_WRITE_10 0x05 +#define K_FW_ERASE_10 0x06 +#define K_FW_WRITE_SPARE 0x07 +#define K_FW_READ_SPARE 0x08
+#define K_FW_ERASE_10_FORCE 0x0b +#define K_FW_GET_VERSION 0x0c
+#define K_FW_LBA_READ_10 0x14 +#define K_FW_LBA_WRITE_10 0x15 +#define K_FW_ERASE_SYS_DISK 0x16 +#define K_FW_SDRAM_READ_10 0x17 +#define K_FW_SDRAM_WRITE_10 0x18 +#define K_FW_SDRAM_EXECUTE 0x19 +#define K_FW_READ_FLASH_INFO 0x1A +#define K_FW_GET_CHIP_VER 0x1B +#define K_FW_LOW_FORMAT 0x1C +#define K_FW_SET_RESET_FLAG 0x1E +#define K_FW_SPI_READ_10 0x21 +#define K_FW_SPI_WRITE_10 0x22
+#define K_FW_SESSION 0X30 +#define K_FW_RESET 0xff
+#define CBW_DIRECTION_OUT 0x00 +#define CBW_DIRECTION_IN 0x80
+struct cmd_dispatch_info {
- int cmd;
- void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
----------------------8<---------------------------------------
This should go to f_rockchip.h file
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
- {
.cmd = K_FW_TEST_UNIT_READY,
.cb = cb_test_unit_ready,
- },
- {
.cmd = K_FW_READ_FLASH_ID,
.cb = cb_read_storage_id,
- },
- {
.cmd = K_FW_SET_DEVICE_ID,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_TEST_BAD_BLOCK,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_WRITE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_ERASE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_WRITE_SPARE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_READ_SPARE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_ERASE_10_FORCE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_GET_VERSION,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_LBA_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_LBA_WRITE_10,
.cb = cb_write_lba,
- },
- {
.cmd = K_FW_ERASE_SYS_DISK,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SDRAM_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SDRAM_WRITE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SDRAM_EXECUTE,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_READ_FLASH_INFO,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_GET_CHIP_VER,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_LOW_FORMAT,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SET_RESET_FLAG,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SPI_READ_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SPI_WRITE_10,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_SESSION,
.cb = cb_not_support,
- },
- {
.cmd = K_FW_RESET,
.cb = cb_reboot,
- },
+};
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) +{
- void (*func_cb)(struct usb_ep *ep, struct usb_request *req)
= NULL;
- struct fsg_bulk_cb_wrap cbw
__attribute__((aligned(ARCH_DMA_MINALIGN)));
- int i;
- char *cmdbuf = req->buf;
- if (req->status != 0 || req->length == 0)
^^^^^^^^^^^ req->status is enough
return;
- memcpy((char*)&cbw, req->buf, USB_BULK_CB_WRAP_LEN);
- printcbw(req->buf);
- for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
if (cmd_dispatch_info[i].cmd == cbw.CDB[0]) {
func_cb = cmd_dispatch_info[i].cb;
break;
}
- }
- if (!func_cb) {
error("unknown command: %s", (char*)req->buf);
rockusb_tx_write_str("FAILunknown command");
- } else {
if (req->actual < req->length) {
u8 *buf = (u8 *)req->buf;
buf[req->actual] = 0;
func_cb(ep, req);
} else {
error("buffer overflow");
rockusb_tx_write_str("FAILbuffer overflow");
}
- }
- *cmdbuf = '\0';
- req->actual = 0;
- usb_ep_queue(ep, req, 0);
+}
Despite few minor comments - this is what I've expected.
Please add changelog when pasting your patches.
Also using patman (./tools/patman) could facilitate posting patches.
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

this patch add rockusb command. the usage is rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com --- cmd/Kconfig | 12 +++++++++ cmd/Makefile | 1 + cmd/rockusb.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/rockusb.h | 13 +++++++++ 4 files changed, 105 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 include/rockusb.h
diff --git a/cmd/Kconfig b/cmd/Kconfig index ef53156..dac2cc0 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -475,6 +475,18 @@ config CMD_DFU Enables the command "dfu" which is used to have U-Boot create a DFU class device via USB.
+config CMD_ROCKUSB + bool "rockusb" + select USB_FUNCTION_ROCKUSB + help + Enables the command "rockusb" which is used to have U-Boot create a + Rockusb class device via USB. + +config USB_FUNCTION_ROCKUSB + bool "Enable USB rockusb gadget" + help + This enables the USB part of the rockusb gadget. + config CMD_USB_MASS_STORAGE bool "UMS usb mass storage" help diff --git a/cmd/Makefile b/cmd/Makefile index f13bb8c..f5f1663 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -141,6 +141,7 @@ endif
obj-$(CONFIG_CMD_USB) += usb.o disk.o obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o +obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o diff --git a/cmd/rockusb.c b/cmd/rockusb.c new file mode 100644 index 0000000..f5bd86e --- /dev/null +++ b/cmd/rockusb.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2017 Eddie Cai eddie.cai.linux@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <console.h> +#include <g_dnl.h> +#include <usb.h> +#include <rockusb.h> + + +static int do_rockusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int controller_index, dev_index; + char *usb_controller; + char *devtype; + char *devnum; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + usb_controller = argv[1]; + controller_index = simple_strtoul(usb_controller, NULL, 0); + + if (argc >= 4) { + devtype = argv[2]; + devnum = argv[3]; + } else { + devtype = "mmc"; + devnum = argv[2]; + } + dev_index = simple_strtoul(devnum, NULL, 0); + rockusb_dev_init(devtype, dev_index); + + ret = board_usb_init(controller_index, USB_INIT_DEVICE); + if (ret) { + error("USB init failed: %d", ret); + return CMD_RET_FAILURE; + } + + g_dnl_clear_detach(); + ret = g_dnl_register("usb_dnl_rockusb"); + if (ret) + return ret; + printf("do_rockusb1\n"); + if (!g_dnl_board_usb_cable_connected()) { + puts("\rUSB cable not detected.\n" \ + "Command exit.\n"); + ret = CMD_RET_FAILURE; + goto exit; + } + + while (1) { + if (g_dnl_detach()) + break; + if (ctrlc()) + break; + usb_gadget_handle_interrupts(controller_index); + } + printf("do_rockusb2\n"); + ret = CMD_RET_SUCCESS; + +exit: + g_dnl_unregister(); + g_dnl_clear_detach(); + board_usb_cleanup(controller_index, USB_INIT_DEVICE); + + return ret; +} + +U_BOOT_CMD(rockusb, 4, 1, do_rockusb, + "Use the ROCKUSB", + "rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0\n" + " devtype defaults to mmc" +); diff --git a/include/rockusb.h b/include/rockusb.h new file mode 100644 index 0000000..cdea63d --- /dev/null +++ b/include/rockusb.h @@ -0,0 +1,13 @@ +/* + * (C) Copyright 2017 + * + * Eddie Cai eddie.cai.linux@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef _ROCKUSB_H_ +#define _ROCKUSB_H_ + +void rockusb_dev_init(char *dev_type, int dev_index); + +#endif /* _ROCKUSB_H_ */

Hi Eddie,
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch add rockusb command. the usage is rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
cmd/Kconfig | 12 +++++++++ cmd/Makefile | 1 + cmd/rockusb.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/rockusb.h | 13 +++++++++ 4 files changed, 105 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 include/rockusb.h
Can you please add some documentation on how to use this command and what host tools you need?
diff --git a/cmd/Kconfig b/cmd/Kconfig index ef53156..dac2cc0 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -475,6 +475,18 @@ config CMD_DFU Enables the command "dfu" which is used to have U-Boot create a DFU class device via USB.
+config CMD_ROCKUSB
bool "rockusb"
select USB_FUNCTION_ROCKUSB
help
Enables the command "rockusb" which is used to have U-Boot create a
Rockusb class device via USB.
Does this mean Rockchip-class device?
+config USB_FUNCTION_ROCKUSB
bool "Enable USB rockusb gadget"
help
This enables the USB part of the rockusb gadget.
config CMD_USB_MASS_STORAGE bool "UMS usb mass storage" help diff --git a/cmd/Makefile b/cmd/Makefile index f13bb8c..f5f1663 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -141,6 +141,7 @@ endif
obj-$(CONFIG_CMD_USB) += usb.o disk.o obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o +obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
Can you put it in alphabetical order if possible?
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o diff --git a/cmd/rockusb.c b/cmd/rockusb.c new file mode 100644 index 0000000..f5bd86e --- /dev/null +++ b/cmd/rockusb.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2017 Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <command.h> +#include <console.h> +#include <g_dnl.h> +#include <usb.h> +#include <rockusb.h>
Should go above usb.h
remove extra blank line
+static int do_rockusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{
int controller_index, dev_index;
char *usb_controller;
char *devtype;
char *devnum;
int ret;
if (argc < 2)
return CMD_RET_USAGE;
usb_controller = argv[1];
controller_index = simple_strtoul(usb_controller, NULL, 0);
if (argc >= 4) {
devtype = argv[2];
devnum = argv[3];
} else {
devtype = "mmc";
devnum = argv[2];
}
dev_index = simple_strtoul(devnum, NULL, 0);
rockusb_dev_init(devtype, dev_index);
Can this fail, e.g. if index is out of range?
ret = board_usb_init(controller_index, USB_INIT_DEVICE);
if (ret) {
error("USB init failed: %d", ret);
return CMD_RET_FAILURE;
}
g_dnl_clear_detach();
ret = g_dnl_register("usb_dnl_rockusb");
if (ret)
return ret;
Commands should return either 0 or CMD_RET_FAILURE.
printf("do_rockusb1\n");
Do you want this?
if (!g_dnl_board_usb_cable_connected()) {
puts("\rUSB cable not detected.\n" \
"Command exit.\n");
ret = CMD_RET_FAILURE;
goto exit;
}
while (1) {
if (g_dnl_detach())
break;
if (ctrlc())
break;
usb_gadget_handle_interrupts(controller_index);
}
printf("do_rockusb2\n");
Do you want this?
ret = CMD_RET_SUCCESS;
+exit:
g_dnl_unregister();
g_dnl_clear_detach();
board_usb_cleanup(controller_index, USB_INIT_DEVICE);
return ret;
+}
+U_BOOT_CMD(rockusb, 4, 1, do_rockusb,
"Use the ROCKUSB",
Can you add a little more here?
"rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0\n"
" devtype defaults to mmc"
+); diff --git a/include/rockusb.h b/include/rockusb.h new file mode 100644 index 0000000..cdea63d --- /dev/null +++ b/include/rockusb.h
Can this go in include/asm instead?
@@ -0,0 +1,13 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _ROCKUSB_H_ +#define _ROCKUSB_H_
+void rockusb_dev_init(char *dev_type, int dev_index);
Please add a function comment.
+#endif /* _ROCKUSB_H_ */
2.7.4
Regards, Simon

Hi Simon
2017-03-20 10:29 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie,
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch add rockusb command. the usage is rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
cmd/Kconfig | 12 +++++++++ cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++++++++++++++++++++++++++++
+++++++++++++++++++++++++
include/rockusb.h | 13 +++++++++ 4 files changed, 105 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 include/rockusb.h
Can you please add some documentation on how to use this command and what host tools you need?
Sure, I will add README.rockusb in next version
diff --git a/cmd/Kconfig b/cmd/Kconfig index ef53156..dac2cc0 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -475,6 +475,18 @@ config CMD_DFU Enables the command "dfu" which is used to have U-Boot create
a DFU
class device via USB.
+config CMD_ROCKUSB
bool "rockusb"
select USB_FUNCTION_ROCKUSB
help
Enables the command "rockusb" which is used to have U-Boot
create a
Rockusb class device via USB.
Does this mean Rockchip-class device?
Yes, This is vendor specific class.
+config USB_FUNCTION_ROCKUSB
bool "Enable USB rockusb gadget"
help
This enables the USB part of the rockusb gadget.
config CMD_USB_MASS_STORAGE bool "UMS usb mass storage" help diff --git a/cmd/Makefile b/cmd/Makefile index f13bb8c..f5f1663 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -141,6 +141,7 @@ endif
obj-$(CONFIG_CMD_USB) += usb.o disk.o obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o +obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
Can you put it in alphabetical order if possible?
Sure, I will try to put it in alphabetical order in next version
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o diff --git a/cmd/rockusb.c b/cmd/rockusb.c new file mode 100644 index 0000000..f5bd86e --- /dev/null +++ b/cmd/rockusb.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2017 Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <command.h> +#include <console.h> +#include <g_dnl.h> +#include <usb.h> +#include <rockusb.h>
Should go above usb.h
done
remove extra blank line
done
+static int do_rockusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const
argv[])
+{
int controller_index, dev_index;
char *usb_controller;
char *devtype;
char *devnum;
int ret;
if (argc < 2)
return CMD_RET_USAGE;
usb_controller = argv[1];
controller_index = simple_strtoul(usb_controller, NULL, 0);
if (argc >= 4) {
devtype = argv[2];
devnum = argv[3];
} else {
devtype = "mmc";
devnum = argv[2];
}
dev_index = simple_strtoul(devnum, NULL, 0);
rockusb_dev_init(devtype, dev_index);
Can this fail, e.g. if index is out of range?
I will add a return value in next version
ret = board_usb_init(controller_index, USB_INIT_DEVICE);
if (ret) {
error("USB init failed: %d", ret);
return CMD_RET_FAILURE;
}
g_dnl_clear_detach();
ret = g_dnl_register("usb_dnl_rockusb");
if (ret)
return ret;
Commands should return either 0 or CMD_RET_FAILURE.
OK, i will fix it in next version.
printf("do_rockusb1\n");
Do you want this?
Oops, i will remove it in next version.
if (!g_dnl_board_usb_cable_connected()) {
puts("\rUSB cable not detected.\n" \
"Command exit.\n");
ret = CMD_RET_FAILURE;
goto exit;
}
while (1) {
if (g_dnl_detach())
break;
if (ctrlc())
break;
usb_gadget_handle_interrupts(controller_index);
}
printf("do_rockusb2\n");
Do you want this?
i will remove it in next version.
ret = CMD_RET_SUCCESS;
+exit:
g_dnl_unregister();
g_dnl_clear_detach();
board_usb_cleanup(controller_index, USB_INIT_DEVICE);
return ret;
+}
+U_BOOT_CMD(rockusb, 4, 1, do_rockusb,
"Use the ROCKUSB",
Can you add a little more here?
sure
"rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0
mmc 0\n"
" devtype defaults to mmc"
+); diff --git a/include/rockusb.h b/include/rockusb.h new file mode 100644 index 0000000..cdea63d --- /dev/null +++ b/include/rockusb.h
Can this go in include/asm instead?
do you mean include/asm-generic ? may i know why ?
@@ -0,0 +1,13 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _ROCKUSB_H_ +#define _ROCKUSB_H_
+void rockusb_dev_init(char *dev_type, int dev_index);
Please add a function comment.
OK, i will add a function comment in next version .
+#endif /* _ROCKUSB_H_ */
2.7.4
Regards, Simon

Hi Eddie,
On 20 March 2017 at 02:14, Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Simon
2017-03-20 10:29 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie,
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch add rockusb command. the usage is rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
cmd/Kconfig | 12 +++++++++ cmd/Makefile | 1 + cmd/rockusb.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/rockusb.h | 13 +++++++++ 4 files changed, 105 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 include/rockusb.h
[..]
"rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0
mmc 0\n"
" devtype defaults to mmc"
+); diff --git a/include/rockusb.h b/include/rockusb.h new file mode 100644 index 0000000..cdea63d --- /dev/null +++ b/include/rockusb.h
Can this go in include/asm instead?
do you mean include/asm-generic ? may i know why ?
No I was thinking of arch/arm/include/asm/arch-rockchip. Because this is a rockchip-specific file, isn't it?
Regards, Simon

Hi Eddie,
this patch add rockusb command. the usage is rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb 0 mmc 0
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
cmd/Kconfig | 12 +++++++++ cmd/Makefile | 1 + cmd/rockusb.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/rockusb.h | 13 +++++++++ 4 files changed, 105 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 include/rockusb.h
diff --git a/cmd/Kconfig b/cmd/Kconfig index ef53156..dac2cc0 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -475,6 +475,18 @@ config CMD_DFU Enables the command "dfu" which is used to have U-Boot create a DFU class device via USB.
+config CMD_ROCKUSB
bool "rockusb"
select USB_FUNCTION_ROCKUSB
help
Enables the command "rockusb" which is used to have U-Boot
create a
Rockusb class device via USB.
+config USB_FUNCTION_ROCKUSB
bool "Enable USB rockusb gadget"
help
This enables the USB part of the rockusb gadget.
config CMD_USB_MASS_STORAGE bool "UMS usb mass storage" help diff --git a/cmd/Makefile b/cmd/Makefile index f13bb8c..f5f1663 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -141,6 +141,7 @@ endif
obj-$(CONFIG_CMD_USB) += usb.o disk.o obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o +obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o diff --git a/cmd/rockusb.c b/cmd/rockusb.c new file mode 100644 index 0000000..f5bd86e --- /dev/null +++ b/cmd/rockusb.c @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2017 Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <command.h> +#include <console.h> +#include <g_dnl.h> +#include <usb.h> +#include <rockusb.h>
Please remove the extra blank here. (also run your patches through ./scripts/checkpatch.pl before submission.
+static int do_rockusb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{
- int controller_index, dev_index;
- char *usb_controller;
- char *devtype;
- char *devnum;
- int ret;
- if (argc < 2)
return CMD_RET_USAGE;
- usb_controller = argv[1];
- controller_index = simple_strtoul(usb_controller, NULL, 0);
- if (argc >= 4) {
devtype = argv[2];
devnum = argv[3];
- } else {
devtype = "mmc";
devnum = argv[2];
- }
I would prefer to force the whole command syntax support:
"rockchip 0 mmc 0" to comply with other commands (like thor, dfu).
Instead of "rockchip 0 0" and imply the mmc.
- dev_index = simple_strtoul(devnum, NULL, 0);
- rockusb_dev_init(devtype, dev_index);
- ret = board_usb_init(controller_index, USB_INIT_DEVICE);
- if (ret) {
error("USB init failed: %d", ret);
return CMD_RET_FAILURE;
- }
- g_dnl_clear_detach();
- ret = g_dnl_register("usb_dnl_rockusb");
- if (ret)
return ret;
- printf("do_rockusb1\n");
^^^^^^^^^^^^^^^^^^^^^^^^ this should be either removed or rewritten as "debug(...)".
- if (!g_dnl_board_usb_cable_connected()) {
puts("\rUSB cable not detected.\n" \
"Command exit.\n");
ret = CMD_RET_FAILURE;
goto exit;
- }
- while (1) {
if (g_dnl_detach())
break;
if (ctrlc())
break;
usb_gadget_handle_interrupts(controller_index);
- }
- printf("do_rockusb2\n");
- ret = CMD_RET_SUCCESS;
+exit:
- g_dnl_unregister();
- g_dnl_clear_detach();
- board_usb_cleanup(controller_index, USB_INIT_DEVICE);
- return ret;
+}
+U_BOOT_CMD(rockusb, 4, 1, do_rockusb,
- "Use the ROCKUSB",
- "rockusb <USB_controller> [<devtype>] <devnum> e.g. rockusb
0 mmc 0\n"
- " devtype defaults to mmc"
[<devtype>] should be mandatory.
+); diff --git a/include/rockusb.h b/include/rockusb.h new file mode 100644 index 0000000..cdea63d --- /dev/null +++ b/include/rockusb.h @@ -0,0 +1,13 @@ +/*
- (C) Copyright 2017
- Eddie Cai eddie.cai.linux@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef _ROCKUSB_H_ +#define _ROCKUSB_H_
+void rockusb_dev_init(char *dev_type, int dev_index);
+#endif /* _ROCKUSB_H_ */
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com --- include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB + /* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE #define CONFIG_CMD_USB_MASS_STORAGE

Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_CMD_USB_MASS_STORAGE
2.7.4
Regards, Simon

Hi Simon
2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
OK, I will move it to Kconfig.
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_
common.h
index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_CMD_USB_MASS_STORAGE
2.7.4
Regards, Simon

Hi Simon 2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
since rockusb used so widely on rockchip soc based devices. every rockchip soc based device should support it. So I would like to put it in rk3288_common.h or even rockchip-common.h. what do you think?
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_CMD_USB_MASS_STORAGE
2.7.4
Regards, Simon

Hi Eddie,
On 2 May 2017 at 04:37, Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Simon 2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
since rockusb used so widely on rockchip soc based devices. every rockchip soc based device should support it. So I would like to put it in rk3288_common.h or even rockchip-common.h. what do you think?
We are moving to removing the board config headers so cannot add new non-Kconfig CONFIG options.
You can add it to arch/arm/Kconfig - e.g. with 'imply CONFIG_....' under 'config ARCH_ROCKCHIP'.
Please help to remove any options you can from the headers.
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_CMD_USB_MASS_STORAGE
2.7.4
Regards, Simon

Hi Simon
2017-05-03 18:09 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie,
On 2 May 2017 at 04:37, Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Simon 2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
since rockusb used so widely on rockchip soc based devices. every rockchip soc based device should support it. So I would like to put it in rk3288_common.h or even rockchip-common.h. what do you think?
We are moving to removing the board config headers so cannot add new non-Kconfig CONFIG options.
You can add it to arch/arm/Kconfig - e.g. with 'imply CONFIG_....' under 'config ARCH_ROCKCHIP'.
USB_FUNCTION_ROCKUSB depend on USB_GADGET, USB_GADGET_DOWNLOAD, CONFIG_G_DNL_VENDOR_NUM, CONFIG_G_DNL_PRODUCT_NUM should i move those config to arch/arm/Kconfig? how to define CONFIG_G_DNL_VENDOR_NUM and CONFIG_G_DNL_PRODUCT_NUM when select it?
Please help to remove any options you can from the headers.
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_CMD_USB_MASS_STORAGE
2.7.4
Regards, Simon

Hi Eddie, Simon,
Hi Simon
2017-05-03 18:09 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie,
On 2 May 2017 at 04:37, Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Simon 2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
since rockusb used so widely on rockchip soc based devices. every rockchip soc based device should support it. So I would like to put it in rk3288_common.h or even rockchip-common.h. what do you think?
We are moving to removing the board config headers so cannot add new non-Kconfig CONFIG options.
You can add it to arch/arm/Kconfig - e.g. with 'imply CONFIG_....' under 'config ARCH_ROCKCHIP'.
USB_FUNCTION_ROCKUSB depend on USB_GADGET, USB_GADGET_DOWNLOAD, CONFIG_G_DNL_VENDOR_NUM, CONFIG_G_DNL_PRODUCT_NUM should i move those config to arch/arm/Kconfig? how to define CONFIG_G_DNL_VENDOR_NUM and CONFIG_G_DNL_PRODUCT_NUM when select it?
I would prefer to keep those CONFIG options as they are now (and are in sync with other gadgets).
The problem here is that the gadget infrastructure is a bit "problematic" from the device model point of view.
It has his own "structure" borrowed from Linux kernel.
I've poked around and it seems like adding it to DM requires calling "g_dnl_register()" with embedded name of the gadget (like "usb_dnl_dfu").
And such call is required for each different gadget (like mass storage, dfu, fastboot).
Or maybe we should add "stub" DM support to only indicate supported gadgets (like dfu, ums, etc) and leave as much code untouched as possible?
Please help to remove any options you can from the headers.
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_CMD_USB_MASS_STORAGE
2.7.4
Regards, Simon
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

Hi,
On 4 May 2017 at 03:19, Lukasz Majewski lukma@denx.de wrote:
Hi Eddie, Simon,
Hi Simon
2017-05-03 18:09 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie,
On 2 May 2017 at 04:37, Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Simon 2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote:
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
since rockusb used so widely on rockchip soc based devices. every rockchip soc based device should support it. So I would like to put it in rk3288_common.h or even rockchip-common.h. what do you think?
We are moving to removing the board config headers so cannot add new non-Kconfig CONFIG options.
You can add it to arch/arm/Kconfig - e.g. with 'imply CONFIG_....' under 'config ARCH_ROCKCHIP'.
USB_FUNCTION_ROCKUSB depend on USB_GADGET, USB_GADGET_DOWNLOAD, CONFIG_G_DNL_VENDOR_NUM, CONFIG_G_DNL_PRODUCT_NUM should i move those config to arch/arm/Kconfig? how to define CONFIG_G_DNL_VENDOR_NUM and CONFIG_G_DNL_PRODUCT_NUM when select it?
I would prefer to keep those CONFIG options as they are now (and are in sync with other gadgets).
These two are new though right?
CONFIG_CMD_ROCKUSB CONFIG_USB_FUNCTION_ROCKUSB
So they should be added to Kconfig. If they 'depend' on non-Kconfig options, that's fine IMO. We can't express that until the other options are converted.
Let's convert them soon!
The problem here is that the gadget infrastructure is a bit "problematic" from the device model point of view.
It has his own "structure" borrowed from Linux kernel.
I've poked around and it seems like adding it to DM requires calling "g_dnl_register()" with embedded name of the gadget (like "usb_dnl_dfu").
And such call is required for each different gadget (like mass storage, dfu, fastboot).
Or maybe we should add "stub" DM support to only indicate supported gadgets (like dfu, ums, etc) and leave as much code untouched as possible?
I'm sure this can be resolved in some way. I admit I have not looked at it but was thinking of attacking usb_tty sometime, so perhaps might see if I can figure it out.
Please help to remove any options you can from the headers.
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE
#define CONFIG_CMD_USB_MASS_STORAGE
2.7.4
Regards, Simon
Regards, Simon

2017-05-05 0:49 GMT+08:00 Simon Glass sjg@chromium.org:
Hi,
On 4 May 2017 at 03:19, Lukasz Majewski lukma@denx.de wrote:
Hi Eddie, Simon,
Hi Simon
2017-05-03 18:09 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie,
On 2 May 2017 at 04:37, Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Simon 2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie.
On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com wrote: > this patch enable rockusb support on rk3288 based device. > > Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com > --- > include/configs/rk3288_common.h | 4 ++++ > 1 file changed, 4 insertions(+)
I think this should be done in Kconfig.
since rockusb used so widely on rockchip soc based devices. every rockchip soc based device should support it. So I would like to put it in rk3288_common.h or even rockchip-common.h. what do you think?
We are moving to removing the board config headers so cannot add new non-Kconfig CONFIG options.
You can add it to arch/arm/Kconfig - e.g. with 'imply CONFIG_....' under 'config ARCH_ROCKCHIP'.
USB_FUNCTION_ROCKUSB depend on USB_GADGET, USB_GADGET_DOWNLOAD, CONFIG_G_DNL_VENDOR_NUM, CONFIG_G_DNL_PRODUCT_NUM should i move those config to arch/arm/Kconfig? how to define CONFIG_G_DNL_VENDOR_NUM and CONFIG_G_DNL_PRODUCT_NUM when select it?
I would prefer to keep those CONFIG options as they are now (and are in sync with other gadgets).
These two are new though right?
CONFIG_CMD_ROCKUSB CONFIG_USB_FUNCTION_ROCKUSB
So they should be added to Kconfig. If they 'depend' on non-Kconfig options, that's fine IMO. We can't express that until the other options are converted.
Let's convert them soon!
Does it means i can keep it in rk3288_common.h?
The problem here is that the gadget infrastructure is a bit "problematic" from the device model point of view.
It has his own "structure" borrowed from Linux kernel.
I've poked around and it seems like adding it to DM requires calling "g_dnl_register()" with embedded name of the gadget (like "usb_dnl_dfu").
And such call is required for each different gadget (like mass storage, dfu, fastboot).
Or maybe we should add "stub" DM support to only indicate supported gadgets (like dfu, ums, etc) and leave as much code untouched as possible?
I'm sure this can be resolved in some way. I admit I have not looked at it but was thinking of attacking usb_tty sometime, so perhaps might see if I can figure it out.
Please help to remove any options you can from the headers.
> > diff --git a/include/configs/rk3288_common.h > b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 > --- a/include/configs/rk3288_common.h > +++ b/include/configs/rk3288_common.h > @@ -74,6 +74,10 @@ > #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR > #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000 > > +/* rockusb */ > +#define CONFIG_CMD_ROCKUSB > +#define CONFIG_USB_FUNCTION_ROCKUSB > + > /* usb mass storage */ > #define CONFIG_USB_FUNCTION_MASS_STORAGE > #define CONFIG_CMD_USB_MASS_STORAGE > -- > 2.7.4
Regards, Simon
Regards, Simon

Hi Eddie,
On 4 May 2017 at 19:15, Eddie Cai eddie.cai.linux@gmail.com wrote:
2017-05-05 0:49 GMT+08:00 Simon Glass sjg@chromium.org:
Hi,
On 4 May 2017 at 03:19, Lukasz Majewski lukma@denx.de wrote:
Hi Eddie, Simon,
Hi Simon
2017-05-03 18:09 GMT+08:00 Simon Glass sjg@chromium.org:
Hi Eddie,
On 2 May 2017 at 04:37, Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Simon 2017-03-20 10:30 GMT+08:00 Simon Glass sjg@chromium.org: > Hi Eddie. > > On 15 March 2017 at 01:56, Eddie Cai eddie.cai.linux@gmail.com > wrote: >> this patch enable rockusb support on rk3288 based device. >> >> Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com >> --- >> include/configs/rk3288_common.h | 4 ++++ >> 1 file changed, 4 insertions(+) > > I think this should be done in Kconfig. since rockusb used so widely on rockchip soc based devices. every rockchip soc based device should support it. So I would like to put it in rk3288_common.h or even rockchip-common.h. what do you think?
We are moving to removing the board config headers so cannot add new non-Kconfig CONFIG options.
You can add it to arch/arm/Kconfig - e.g. with 'imply CONFIG_....' under 'config ARCH_ROCKCHIP'.
USB_FUNCTION_ROCKUSB depend on USB_GADGET, USB_GADGET_DOWNLOAD, CONFIG_G_DNL_VENDOR_NUM, CONFIG_G_DNL_PRODUCT_NUM should i move those config to arch/arm/Kconfig? how to define CONFIG_G_DNL_VENDOR_NUM and CONFIG_G_DNL_PRODUCT_NUM when select it?
I would prefer to keep those CONFIG options as they are now (and are in sync with other gadgets).
These two are new though right?
CONFIG_CMD_ROCKUSB CONFIG_USB_FUNCTION_ROCKUSB
So they should be added to Kconfig. If they 'depend' on non-Kconfig options, that's fine IMO. We can't express that until the other options are converted.
Let's convert them soon!
Does it means i can keep it in rk3288_common.h?
Anything new you add must go into defconfig. If it depends on a non-Kconfig option, then just leave out the depend. We cannot add new things to the config whitelist, so you should get a build error if you try to add a new option outside Kconfig.
The problem here is that the gadget infrastructure is a bit "problematic" from the device model point of view.
It has his own "structure" borrowed from Linux kernel.
I've poked around and it seems like adding it to DM requires calling "g_dnl_register()" with embedded name of the gadget (like "usb_dnl_dfu").
And such call is required for each different gadget (like mass storage, dfu, fastboot).
Or maybe we should add "stub" DM support to only indicate supported gadgets (like dfu, ums, etc) and leave as much code untouched as possible?
I'm sure this can be resolved in some way. I admit I have not looked at it but was thinking of attacking usb_tty sometime, so perhaps might see if I can figure it out.
Please help to remove any options you can from the headers.
> >> >> diff --git a/include/configs/rk3288_common.h >> b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 >> --- a/include/configs/rk3288_common.h >> +++ b/include/configs/rk3288_common.h >> @@ -74,6 +74,10 @@ >> #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR >> #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000 >> >> +/* rockusb */ >> +#define CONFIG_CMD_ROCKUSB >> +#define CONFIG_USB_FUNCTION_ROCKUSB >> + >> /* usb mass storage */ >> #define CONFIG_USB_FUNCTION_MASS_STORAGE >> #define CONFIG_CMD_USB_MASS_STORAGE >> -- >> 2.7.4
Regards, Simon
Regards, Simon
Regards, Simon

Dear Simon, Eddie,
Let's convert them soon!
Does it means i can keep it in rk3288_common.h?
Anything new you add must go into defconfig. If it depends on a non-Kconfig option, then just leave out the depend. We cannot add new things to the config whitelist, so you should get a build error if you try to add a new option outside Kconfig.
Ok. Then I will wait for next iteration....
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

Hi Eddie,
this patch enable rockusb support on rk3288 based device.
Signed-off-by: Eddie Cai eddie.cai.linux@gmail.com
include/configs/rk3288_common.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index b5606d4..b19a34d 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -74,6 +74,10 @@ #define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_LOAD_ADDR #define CONFIG_FASTBOOT_BUF_SIZE 0x08000000
+/* rockusb */ +#define CONFIG_CMD_ROCKUSB +#define CONFIG_USB_FUNCTION_ROCKUSB
/* usb mass storage */ #define CONFIG_USB_FUNCTION_MASS_STORAGE #define CONFIG_CMD_USB_MASS_STORAGE
Reviewed-by: Lukasz Majewski lukma@denx.de
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

On Wed, 15 Mar 2017 15:56:02 +0800 Eddie Cai eddie.cai.linux@gmail.com wrote:
rockusb is a protocol run between host pc and device. it help people get device info, flash image to device. this patch implement rockusb on device side.
Thank you for your patch. I will review it shortly.
If I might ask - is there any high-level documentation (pdf, webpage, etc) describing this protocol?
If yes, please add some very short entry to ./doc repository (e.g. ./doc/README.rockusb).
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++++++++++++ include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

Hi Lukasz
2017-03-15 17:06 GMT+08:00 Lukasz Majewski lukma@denx.de:
On Wed, 15 Mar 2017 15:56:02 +0800 Eddie Cai eddie.cai.linux@gmail.com wrote:
rockusb is a protocol run between host pc and device. it help people get device info, flash image to device. this patch implement rockusb on device side.
Thank you for your patch. I will review it shortly.
If I might ask - is there any high-level documentation (pdf, webpage, etc) describing this protocol?
If yes, please add some very short entry to ./doc repository (e.g. ./doc/README.rockusb).
Thanks for your quick reply. I will add README.rockusb in next version.
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++++++++++++ include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

On Wed, 15 Mar 2017 17:31:27 +0800 Eddie Cai eddie.cai.linux@gmail.com wrote:
Hi Lukasz
2017-03-15 17:06 GMT+08:00 Lukasz Majewski lukma@denx.de:
On Wed, 15 Mar 2017 15:56:02 +0800 Eddie Cai eddie.cai.linux@gmail.com wrote:
rockusb is a protocol run between host pc and device. it help people get device info, flash image to device. this patch implement rockusb on device side.
Thank you for your patch. I will review it shortly.
If I might ask - is there any high-level documentation (pdf, webpage, etc) describing this protocol?
If yes, please add some very short entry to ./doc repository (e.g. ./doc/README.rockusb).
Thanks for your quick reply. I will add README.rockusb in next version.
Great :-)
As a reference, you can look to ./doc/README.dfutftp
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++++++++++++ include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

On 03/15/2017 08:56 AM, Eddie Cai wrote:
rockusb is a protocol run between host pc and device. it help people get device info, flash image to device. this patch implement rockusb on device side.
What is the benefit of this yet-another NIH protocol compared to ie. DFU/UMS/Thor/Fastboot ?
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++++++++++++ include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h

2017-03-17 5:26 GMT+08:00 Marek Vasut marex@denx.de:
On 03/15/2017 08:56 AM, Eddie Cai wrote:
rockusb is a protocol run between host pc and device. it help people get
device
info, flash image to device. this patch implement rockusb on device side.
What is the benefit of this yet-another NIH protocol compared to ie. DFU/UMS/Thor/Fastboot ?
This is mostly used on Rockchip chipset. All the rockchip SoC boot rom and develop tools implement this protocol. So we want to use the same protocol which compatible with current tools.
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++
++++++++++
include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h
-- Best regards, Marek Vasut

On 03/20/2017 02:53 AM, Eddie Cai wrote:
2017-03-17 5:26 GMT+08:00 Marek Vasut marex@denx.de:
On 03/15/2017 08:56 AM, Eddie Cai wrote:
rockusb is a protocol run between host pc and device. it help people get
device
info, flash image to device. this patch implement rockusb on device side.
What is the benefit of this yet-another NIH protocol compared to ie. DFU/UMS/Thor/Fastboot ?
This is mostly used on Rockchip chipset. All the rockchip SoC boot rom and develop tools implement this protocol. So we want to use the same protocol which compatible with current tools.
This does not really answer my question. We have protocols which implement exactly this functionality already, why do we need another one ?

Hi Marek,
On 20 March 2017 at 06:24, Marek Vasut marex@denx.de wrote:
On 03/20/2017 02:53 AM, Eddie Cai wrote:
2017-03-17 5:26 GMT+08:00 Marek Vasut marex@denx.de:
On 03/15/2017 08:56 AM, Eddie Cai wrote:
rockusb is a protocol run between host pc and device. it help people get
device
info, flash image to device. this patch implement rockusb on device side.
What is the benefit of this yet-another NIH protocol compared to ie. DFU/UMS/Thor/Fastboot ?
This is mostly used on Rockchip chipset. All the rockchip SoC boot rom and develop tools implement this protocol. So we want to use the same protocol which compatible with current tools.
This does not really answer my question. We have protocols which implement exactly this functionality already, why do we need another one ?
I think the point is that this is widely used with Rockchip devices, and for mainline U-Boot to be fully useful it needs to support it.
However I do think it would be good to move to using DFU etc. if possible?
Regards, Simon

On 03/20/2017 05:01 PM, Simon Glass wrote:
Hi Marek,
On 20 March 2017 at 06:24, Marek Vasut marex@denx.de wrote:
On 03/20/2017 02:53 AM, Eddie Cai wrote:
2017-03-17 5:26 GMT+08:00 Marek Vasut marex@denx.de:
On 03/15/2017 08:56 AM, Eddie Cai wrote:
rockusb is a protocol run between host pc and device. it help people get
device
info, flash image to device. this patch implement rockusb on device side.
What is the benefit of this yet-another NIH protocol compared to ie. DFU/UMS/Thor/Fastboot ?
This is mostly used on Rockchip chipset. All the rockchip SoC boot rom and develop tools implement this protocol. So we want to use the same protocol which compatible with current tools.
This does not really answer my question. We have protocols which implement exactly this functionality already, why do we need another one ?
I think the point is that this is widely used with Rockchip devices, and for mainline U-Boot to be fully useful it needs to support it.
OK, I'll leave that decision to Lukasz . I'm not a big fan of adding redundant functionality only because someone thought NIH is good before looking at standards.
However I do think it would be good to move to using DFU etc. if possible?
Yes.

Hi Marek,
On 03/21/2017 12:33 AM, Marek Vasut wrote:
On 03/20/2017 05:01 PM, Simon Glass wrote:
Hi Marek,
On 20 March 2017 at 06:24, Marek Vasut marex@denx.de wrote:
On 03/20/2017 02:53 AM, Eddie Cai wrote:
2017-03-17 5:26 GMT+08:00 Marek Vasut marex@denx.de:
On 03/15/2017 08:56 AM, Eddie Cai wrote:
rockusb is a protocol run between host pc and device. it help people get
device
info, flash image to device. this patch implement rockusb on device side.
What is the benefit of this yet-another NIH protocol compared to ie. DFU/UMS/Thor/Fastboot ?
This is mostly used on Rockchip chipset. All the rockchip SoC boot rom and develop tools implement this protocol. So we want to use the same protocol which compatible with current tools.
This does not really answer my question. We have protocols which implement exactly this functionality already, why do we need another one ?
I think the point is that this is widely used with Rockchip devices, and for mainline U-Boot to be fully useful it needs to support it.
OK, I'll leave that decision to Lukasz . I'm not a big fan of adding redundant functionality only because someone thought NIH is good before looking at standards.
I don't know how you define "redundant functionality", from the gadget framework view, yes, it's very similar to other storage based gadget, we may able to re-use the common part of the framework. But it's definitely a different USB class driver which is used in Rockchip bootrom and Rockchip loader, and some commands like RD(Reset device), DB(download boot) are not able to use in ums or fastboot, but they are useful in Rockchip platform.
Thanks, - Kever
However I do think it would be good to move to using DFU etc. if possible?
Yes.

On Tue, Mar 21, 2017 at 01:17:18PM +0800, Kever Yang wrote:
Hi Marek,
On 03/21/2017 12:33 AM, Marek Vasut wrote:
On 03/20/2017 05:01 PM, Simon Glass wrote:
Hi Marek,
On 20 March 2017 at 06:24, Marek Vasut marex@denx.de wrote:
On 03/20/2017 02:53 AM, Eddie Cai wrote:
2017-03-17 5:26 GMT+08:00 Marek Vasut marex@denx.de:
On 03/15/2017 08:56 AM, Eddie Cai wrote: >rockusb is a protocol run between host pc and device. it help people get device >info, flash image to device. this patch implement rockusb on device side. What is the benefit of this yet-another NIH protocol compared to ie. DFU/UMS/Thor/Fastboot ?
This is mostly used on Rockchip chipset. All the rockchip SoC boot rom and develop tools implement this protocol. So we want to use the same protocol which compatible with current tools.
This does not really answer my question. We have protocols which implement exactly this functionality already, why do we need another one ?
I think the point is that this is widely used with Rockchip devices, and for mainline U-Boot to be fully useful it needs to support it.
OK, I'll leave that decision to Lukasz . I'm not a big fan of adding redundant functionality only because someone thought NIH is good before looking at standards.
I don't know how you define "redundant functionality", from the gadget framework view, yes, it's very similar to other storage based gadget, we may able to re-use the common part of the framework. But it's definitely a different USB class driver which is used in Rockchip bootrom and Rockchip loader, and some commands like RD(Reset device), DB(download boot) are not able to use in ums or fastboot, but they are useful in Rockchip platform.
So here's my two cents. At the back end side of things, DFU, fastboot, UMS, Thor, rockusb and whatever comes down the pipe next should all be able to share a good bit of back end code, in a common way (and maybe we can even address DFU using the CLI rather than API to do things) as it all boils down to "take data via USB, write to defined location" or "do something then reset the board" and so on. And by that same token, while I wish more vendors used the same protocols, we need to support the world that exists, not the world we wish we had.

HI Eddie,
rockusb is a protocol run between host pc and device. it help people get device info, flash image to device. this patch implement rockusb on device side.
I'm a bit confused, since I don't know if you work on v2 of those patches (as Kever Yang pointed out that UMS approach could be re-used here)?
(And just gentle reminder of the README.xxx file to describe this protocol).
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++++++++++++ include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de

Hi Lukasz
2017-03-27 16:27 GMT+08:00 Lukasz Majewski lukma@denx.de:
HI Eddie,
rockusb is a protocol run between host pc and device. it help people get device info, flash image to device. this patch implement rockusb on device side.
I'm a bit confused, since I don't know if you work on v2 of those patches (as Kever Yang pointed out that UMS approach could be re-used here)?
(And just gentle reminder of the README.xxx file to describe this protocol).
I am working on V2 patch. It will reused ums function as more as possible. I won't forget README.rockusb
Eddie Cai (3): drivers: usb: gadget: add the rockusb gadget cmd: add rockusb command rockchip: rk3288: enable rockusb support on rk3288 based device
cmd/Kconfig | 12 + cmd/Makefile | 1 + cmd/rockusb.c | 79 ++++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_rockusb.c | 801 ++++++++++++++++++++++++++++++++++++++++ include/configs/rk3288_common.h | 4 + include/rockusb.h | 13 + 7 files changed, 911 insertions(+) create mode 100644 cmd/rockusb.c create mode 100644 drivers/usb/gadget/f_rockusb.c create mode 100644 include/rockusb.h
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
participants (6)
-
Eddie Cai
-
Kever Yang
-
Lukasz Majewski
-
Marek Vasut
-
Simon Glass
-
Tom Rini