183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2bf2b72beSEddie Cai /* 3bf2b72beSEddie Cai * (C) Copyright 2017 4bf2b72beSEddie Cai * 5bf2b72beSEddie Cai * Eddie Cai <eddie.cai.linux@gmail.com> 6bf2b72beSEddie Cai */ 7bf2b72beSEddie Cai #include <config.h> 8bf2b72beSEddie Cai #include <common.h> 9bf2b72beSEddie Cai #include <errno.h> 10bf2b72beSEddie Cai #include <malloc.h> 11bf2b72beSEddie Cai #include <memalign.h> 12bf2b72beSEddie Cai #include <linux/usb/ch9.h> 13bf2b72beSEddie Cai #include <linux/usb/gadget.h> 14bf2b72beSEddie Cai #include <linux/usb/composite.h> 15bf2b72beSEddie Cai #include <linux/compiler.h> 16bf2b72beSEddie Cai #include <version.h> 17bf2b72beSEddie Cai #include <g_dnl.h> 18bf2b72beSEddie Cai #include <asm/arch/f_rockusb.h> 19bf2b72beSEddie Cai 20bf2b72beSEddie Cai static inline struct f_rockusb *func_to_rockusb(struct usb_function *f) 21bf2b72beSEddie Cai { 22bf2b72beSEddie Cai return container_of(f, struct f_rockusb, usb_function); 23bf2b72beSEddie Cai } 24bf2b72beSEddie Cai 25bf2b72beSEddie Cai static struct usb_endpoint_descriptor fs_ep_in = { 26bf2b72beSEddie Cai .bLength = USB_DT_ENDPOINT_SIZE, 27bf2b72beSEddie Cai .bDescriptorType = USB_DT_ENDPOINT, 28bf2b72beSEddie Cai .bEndpointAddress = USB_DIR_IN, 29bf2b72beSEddie Cai .bmAttributes = USB_ENDPOINT_XFER_BULK, 30bf2b72beSEddie Cai .wMaxPacketSize = cpu_to_le16(64), 31bf2b72beSEddie Cai }; 32bf2b72beSEddie Cai 33bf2b72beSEddie Cai static struct usb_endpoint_descriptor fs_ep_out = { 34bf2b72beSEddie Cai .bLength = USB_DT_ENDPOINT_SIZE, 35bf2b72beSEddie Cai .bDescriptorType = USB_DT_ENDPOINT, 36bf2b72beSEddie Cai .bEndpointAddress = USB_DIR_OUT, 37bf2b72beSEddie Cai .bmAttributes = USB_ENDPOINT_XFER_BULK, 38bf2b72beSEddie Cai .wMaxPacketSize = cpu_to_le16(64), 39bf2b72beSEddie Cai }; 40bf2b72beSEddie Cai 41bf2b72beSEddie Cai static struct usb_endpoint_descriptor hs_ep_in = { 42bf2b72beSEddie Cai .bLength = USB_DT_ENDPOINT_SIZE, 43bf2b72beSEddie Cai .bDescriptorType = USB_DT_ENDPOINT, 44bf2b72beSEddie Cai .bEndpointAddress = USB_DIR_IN, 45bf2b72beSEddie Cai .bmAttributes = USB_ENDPOINT_XFER_BULK, 46bf2b72beSEddie Cai .wMaxPacketSize = cpu_to_le16(512), 47bf2b72beSEddie Cai }; 48bf2b72beSEddie Cai 49bf2b72beSEddie Cai static struct usb_endpoint_descriptor hs_ep_out = { 50bf2b72beSEddie Cai .bLength = USB_DT_ENDPOINT_SIZE, 51bf2b72beSEddie Cai .bDescriptorType = USB_DT_ENDPOINT, 52bf2b72beSEddie Cai .bEndpointAddress = USB_DIR_OUT, 53bf2b72beSEddie Cai .bmAttributes = USB_ENDPOINT_XFER_BULK, 54bf2b72beSEddie Cai .wMaxPacketSize = cpu_to_le16(512), 55bf2b72beSEddie Cai }; 56bf2b72beSEddie Cai 57bf2b72beSEddie Cai static struct usb_interface_descriptor interface_desc = { 58bf2b72beSEddie Cai .bLength = USB_DT_INTERFACE_SIZE, 59bf2b72beSEddie Cai .bDescriptorType = USB_DT_INTERFACE, 60bf2b72beSEddie Cai .bInterfaceNumber = 0x00, 61bf2b72beSEddie Cai .bAlternateSetting = 0x00, 62bf2b72beSEddie Cai .bNumEndpoints = 0x02, 63bf2b72beSEddie Cai .bInterfaceClass = ROCKUSB_INTERFACE_CLASS, 64bf2b72beSEddie Cai .bInterfaceSubClass = ROCKUSB_INTERFACE_SUB_CLASS, 65bf2b72beSEddie Cai .bInterfaceProtocol = ROCKUSB_INTERFACE_PROTOCOL, 66bf2b72beSEddie Cai }; 67bf2b72beSEddie Cai 68bf2b72beSEddie Cai static struct usb_descriptor_header *rkusb_fs_function[] = { 69bf2b72beSEddie Cai (struct usb_descriptor_header *)&interface_desc, 70bf2b72beSEddie Cai (struct usb_descriptor_header *)&fs_ep_in, 71bf2b72beSEddie Cai (struct usb_descriptor_header *)&fs_ep_out, 72bf2b72beSEddie Cai }; 73bf2b72beSEddie Cai 74bf2b72beSEddie Cai static struct usb_descriptor_header *rkusb_hs_function[] = { 75bf2b72beSEddie Cai (struct usb_descriptor_header *)&interface_desc, 76bf2b72beSEddie Cai (struct usb_descriptor_header *)&hs_ep_in, 77bf2b72beSEddie Cai (struct usb_descriptor_header *)&hs_ep_out, 78bf2b72beSEddie Cai NULL, 79bf2b72beSEddie Cai }; 80bf2b72beSEddie Cai 81bf2b72beSEddie Cai static const char rkusb_name[] = "Rockchip Rockusb"; 82bf2b72beSEddie Cai 83bf2b72beSEddie Cai static struct usb_string rkusb_string_defs[] = { 84bf2b72beSEddie Cai [0].s = rkusb_name, 85bf2b72beSEddie Cai { } /* end of list */ 86bf2b72beSEddie Cai }; 87bf2b72beSEddie Cai 88bf2b72beSEddie Cai static struct usb_gadget_strings stringtab_rkusb = { 89bf2b72beSEddie Cai .language = 0x0409, /* en-us */ 90bf2b72beSEddie Cai .strings = rkusb_string_defs, 91bf2b72beSEddie Cai }; 92bf2b72beSEddie Cai 93bf2b72beSEddie Cai static struct usb_gadget_strings *rkusb_strings[] = { 94bf2b72beSEddie Cai &stringtab_rkusb, 95bf2b72beSEddie Cai NULL, 96bf2b72beSEddie Cai }; 97bf2b72beSEddie Cai 98bf2b72beSEddie Cai static struct f_rockusb *rockusb_func; 99bf2b72beSEddie Cai static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); 100bf2b72beSEddie Cai static int rockusb_tx_write_csw(u32 tag, int residue, u8 status, int size); 101bf2b72beSEddie Cai 102bf2b72beSEddie Cai struct f_rockusb *get_rkusb(void) 103bf2b72beSEddie Cai { 104bf2b72beSEddie Cai struct f_rockusb *f_rkusb = rockusb_func; 105bf2b72beSEddie Cai 106bf2b72beSEddie Cai if (!f_rkusb) { 107bf2b72beSEddie Cai f_rkusb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_rkusb)); 108bf2b72beSEddie Cai if (!f_rkusb) 109bf2b72beSEddie Cai return 0; 110bf2b72beSEddie Cai 111bf2b72beSEddie Cai rockusb_func = f_rkusb; 112bf2b72beSEddie Cai memset(f_rkusb, 0, sizeof(*f_rkusb)); 113bf2b72beSEddie Cai } 114bf2b72beSEddie Cai 115bf2b72beSEddie Cai if (!f_rkusb->buf_head) { 116bf2b72beSEddie Cai f_rkusb->buf_head = memalign(CONFIG_SYS_CACHELINE_SIZE, 117bf2b72beSEddie Cai RKUSB_BUF_SIZE); 118bf2b72beSEddie Cai if (!f_rkusb->buf_head) 119bf2b72beSEddie Cai return 0; 120bf2b72beSEddie Cai 121bf2b72beSEddie Cai f_rkusb->buf = f_rkusb->buf_head; 122bf2b72beSEddie Cai memset(f_rkusb->buf_head, 0, RKUSB_BUF_SIZE); 123bf2b72beSEddie Cai } 124bf2b72beSEddie Cai return f_rkusb; 125bf2b72beSEddie Cai } 126bf2b72beSEddie Cai 127bf2b72beSEddie Cai static struct usb_endpoint_descriptor *rkusb_ep_desc( 128bf2b72beSEddie Cai struct usb_gadget *g, 129bf2b72beSEddie Cai struct usb_endpoint_descriptor *fs, 130bf2b72beSEddie Cai struct usb_endpoint_descriptor *hs) 131bf2b72beSEddie Cai { 132bf2b72beSEddie Cai if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) 133bf2b72beSEddie Cai return hs; 134bf2b72beSEddie Cai return fs; 135bf2b72beSEddie Cai } 136bf2b72beSEddie Cai 137bf2b72beSEddie Cai static void rockusb_complete(struct usb_ep *ep, struct usb_request *req) 138bf2b72beSEddie Cai { 139bf2b72beSEddie Cai int status = req->status; 140bf2b72beSEddie Cai 141bf2b72beSEddie Cai if (!status) 142bf2b72beSEddie Cai return; 143bf2b72beSEddie Cai debug("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual); 144bf2b72beSEddie Cai } 145bf2b72beSEddie Cai 146bf2b72beSEddie Cai /* config the rockusb device*/ 147bf2b72beSEddie Cai static int rockusb_bind(struct usb_configuration *c, struct usb_function *f) 148bf2b72beSEddie Cai { 149bf2b72beSEddie Cai int id; 150bf2b72beSEddie Cai struct usb_gadget *gadget = c->cdev->gadget; 151bf2b72beSEddie Cai struct f_rockusb *f_rkusb = func_to_rockusb(f); 152bf2b72beSEddie Cai const char *s; 153bf2b72beSEddie Cai 154bf2b72beSEddie Cai id = usb_interface_id(c, f); 155bf2b72beSEddie Cai if (id < 0) 156bf2b72beSEddie Cai return id; 157bf2b72beSEddie Cai interface_desc.bInterfaceNumber = id; 158bf2b72beSEddie Cai 159bf2b72beSEddie Cai id = usb_string_id(c->cdev); 160bf2b72beSEddie Cai if (id < 0) 161bf2b72beSEddie Cai return id; 162bf2b72beSEddie Cai 163bf2b72beSEddie Cai rkusb_string_defs[0].id = id; 164bf2b72beSEddie Cai interface_desc.iInterface = id; 165bf2b72beSEddie Cai 166bf2b72beSEddie Cai f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in); 167bf2b72beSEddie Cai if (!f_rkusb->in_ep) 168bf2b72beSEddie Cai return -ENODEV; 169bf2b72beSEddie Cai f_rkusb->in_ep->driver_data = c->cdev; 170bf2b72beSEddie Cai 171bf2b72beSEddie Cai f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out); 172bf2b72beSEddie Cai if (!f_rkusb->out_ep) 173bf2b72beSEddie Cai return -ENODEV; 174bf2b72beSEddie Cai f_rkusb->out_ep->driver_data = c->cdev; 175bf2b72beSEddie Cai 176bf2b72beSEddie Cai f->descriptors = rkusb_fs_function; 177bf2b72beSEddie Cai 178bf2b72beSEddie Cai if (gadget_is_dualspeed(gadget)) { 179bf2b72beSEddie Cai hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress; 180bf2b72beSEddie Cai hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress; 181bf2b72beSEddie Cai f->hs_descriptors = rkusb_hs_function; 182bf2b72beSEddie Cai } 183bf2b72beSEddie Cai 184bf2b72beSEddie Cai s = env_get("serial#"); 185bf2b72beSEddie Cai if (s) 186bf2b72beSEddie Cai g_dnl_set_serialnumber((char *)s); 187bf2b72beSEddie Cai 188bf2b72beSEddie Cai return 0; 189bf2b72beSEddie Cai } 190bf2b72beSEddie Cai 191bf2b72beSEddie Cai static void rockusb_unbind(struct usb_configuration *c, struct usb_function *f) 192bf2b72beSEddie Cai { 193bf2b72beSEddie Cai /* clear the configuration*/ 194bf2b72beSEddie Cai memset(rockusb_func, 0, sizeof(*rockusb_func)); 195bf2b72beSEddie Cai } 196bf2b72beSEddie Cai 197bf2b72beSEddie Cai static void rockusb_disable(struct usb_function *f) 198bf2b72beSEddie Cai { 199bf2b72beSEddie Cai struct f_rockusb *f_rkusb = func_to_rockusb(f); 200bf2b72beSEddie Cai 201bf2b72beSEddie Cai usb_ep_disable(f_rkusb->out_ep); 202bf2b72beSEddie Cai usb_ep_disable(f_rkusb->in_ep); 203bf2b72beSEddie Cai 204bf2b72beSEddie Cai if (f_rkusb->out_req) { 205bf2b72beSEddie Cai free(f_rkusb->out_req->buf); 206bf2b72beSEddie Cai usb_ep_free_request(f_rkusb->out_ep, f_rkusb->out_req); 207bf2b72beSEddie Cai f_rkusb->out_req = NULL; 208bf2b72beSEddie Cai } 209bf2b72beSEddie Cai if (f_rkusb->in_req) { 210bf2b72beSEddie Cai free(f_rkusb->in_req->buf); 211bf2b72beSEddie Cai usb_ep_free_request(f_rkusb->in_ep, f_rkusb->in_req); 212bf2b72beSEddie Cai f_rkusb->in_req = NULL; 213bf2b72beSEddie Cai } 214bf2b72beSEddie Cai if (f_rkusb->buf_head) { 215bf2b72beSEddie Cai free(f_rkusb->buf_head); 216bf2b72beSEddie Cai f_rkusb->buf_head = NULL; 217bf2b72beSEddie Cai f_rkusb->buf = NULL; 218bf2b72beSEddie Cai } 219bf2b72beSEddie Cai } 220bf2b72beSEddie Cai 221bf2b72beSEddie Cai static struct usb_request *rockusb_start_ep(struct usb_ep *ep) 222bf2b72beSEddie Cai { 223bf2b72beSEddie Cai struct usb_request *req; 224bf2b72beSEddie Cai 225bf2b72beSEddie Cai req = usb_ep_alloc_request(ep, 0); 226bf2b72beSEddie Cai if (!req) 227bf2b72beSEddie Cai return NULL; 228bf2b72beSEddie Cai 229bf2b72beSEddie Cai req->length = EP_BUFFER_SIZE; 230bf2b72beSEddie Cai req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE); 231bf2b72beSEddie Cai if (!req->buf) { 232bf2b72beSEddie Cai usb_ep_free_request(ep, req); 233bf2b72beSEddie Cai return NULL; 234bf2b72beSEddie Cai } 235bf2b72beSEddie Cai memset(req->buf, 0, req->length); 236bf2b72beSEddie Cai 237bf2b72beSEddie Cai return req; 238bf2b72beSEddie Cai } 239bf2b72beSEddie Cai 240bf2b72beSEddie Cai static int rockusb_set_alt(struct usb_function *f, unsigned int interface, 241bf2b72beSEddie Cai unsigned int alt) 242bf2b72beSEddie Cai { 243bf2b72beSEddie Cai int ret; 244bf2b72beSEddie Cai struct usb_composite_dev *cdev = f->config->cdev; 245bf2b72beSEddie Cai struct usb_gadget *gadget = cdev->gadget; 246bf2b72beSEddie Cai struct f_rockusb *f_rkusb = func_to_rockusb(f); 247bf2b72beSEddie Cai const struct usb_endpoint_descriptor *d; 248bf2b72beSEddie Cai 249bf2b72beSEddie Cai debug("%s: func: %s intf: %d alt: %d\n", 250bf2b72beSEddie Cai __func__, f->name, interface, alt); 251bf2b72beSEddie Cai 252bf2b72beSEddie Cai d = rkusb_ep_desc(gadget, &fs_ep_out, &hs_ep_out); 253bf2b72beSEddie Cai ret = usb_ep_enable(f_rkusb->out_ep, d); 254bf2b72beSEddie Cai if (ret) { 255bf2b72beSEddie Cai printf("failed to enable out ep\n"); 256bf2b72beSEddie Cai return ret; 257bf2b72beSEddie Cai } 258bf2b72beSEddie Cai 259bf2b72beSEddie Cai f_rkusb->out_req = rockusb_start_ep(f_rkusb->out_ep); 260bf2b72beSEddie Cai if (!f_rkusb->out_req) { 261bf2b72beSEddie Cai printf("failed to alloc out req\n"); 262bf2b72beSEddie Cai ret = -EINVAL; 263bf2b72beSEddie Cai goto err; 264bf2b72beSEddie Cai } 265bf2b72beSEddie Cai f_rkusb->out_req->complete = rx_handler_command; 266bf2b72beSEddie Cai 267bf2b72beSEddie Cai d = rkusb_ep_desc(gadget, &fs_ep_in, &hs_ep_in); 268bf2b72beSEddie Cai ret = usb_ep_enable(f_rkusb->in_ep, d); 269bf2b72beSEddie Cai if (ret) { 270bf2b72beSEddie Cai printf("failed to enable in ep\n"); 271bf2b72beSEddie Cai goto err; 272bf2b72beSEddie Cai } 273bf2b72beSEddie Cai 274bf2b72beSEddie Cai f_rkusb->in_req = rockusb_start_ep(f_rkusb->in_ep); 275bf2b72beSEddie Cai if (!f_rkusb->in_req) { 276bf2b72beSEddie Cai printf("failed alloc req in\n"); 277bf2b72beSEddie Cai ret = -EINVAL; 278bf2b72beSEddie Cai goto err; 279bf2b72beSEddie Cai } 280bf2b72beSEddie Cai f_rkusb->in_req->complete = rockusb_complete; 281bf2b72beSEddie Cai 282bf2b72beSEddie Cai ret = usb_ep_queue(f_rkusb->out_ep, f_rkusb->out_req, 0); 283bf2b72beSEddie Cai if (ret) 284bf2b72beSEddie Cai goto err; 285bf2b72beSEddie Cai 286bf2b72beSEddie Cai return 0; 287bf2b72beSEddie Cai err: 288bf2b72beSEddie Cai rockusb_disable(f); 289bf2b72beSEddie Cai return ret; 290bf2b72beSEddie Cai } 291bf2b72beSEddie Cai 292bf2b72beSEddie Cai static int rockusb_add(struct usb_configuration *c) 293bf2b72beSEddie Cai { 294bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 295bf2b72beSEddie Cai int status; 296bf2b72beSEddie Cai 297bf2b72beSEddie Cai debug("%s: cdev: 0x%p\n", __func__, c->cdev); 298bf2b72beSEddie Cai 299bf2b72beSEddie Cai f_rkusb->usb_function.name = "f_rockusb"; 300bf2b72beSEddie Cai f_rkusb->usb_function.bind = rockusb_bind; 301bf2b72beSEddie Cai f_rkusb->usb_function.unbind = rockusb_unbind; 302bf2b72beSEddie Cai f_rkusb->usb_function.set_alt = rockusb_set_alt; 303bf2b72beSEddie Cai f_rkusb->usb_function.disable = rockusb_disable; 304bf2b72beSEddie Cai f_rkusb->usb_function.strings = rkusb_strings; 305bf2b72beSEddie Cai 306bf2b72beSEddie Cai status = usb_add_function(c, &f_rkusb->usb_function); 307bf2b72beSEddie Cai if (status) { 308bf2b72beSEddie Cai free(f_rkusb); 309bf2b72beSEddie Cai rockusb_func = f_rkusb; 310bf2b72beSEddie Cai } 311bf2b72beSEddie Cai return status; 312bf2b72beSEddie Cai } 313bf2b72beSEddie Cai 314bf2b72beSEddie Cai void rockusb_dev_init(char *dev_type, int dev_index) 315bf2b72beSEddie Cai { 316bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 317bf2b72beSEddie Cai 318bf2b72beSEddie Cai f_rkusb->dev_type = dev_type; 319bf2b72beSEddie Cai f_rkusb->dev_index = dev_index; 320bf2b72beSEddie Cai } 321bf2b72beSEddie Cai 322bf2b72beSEddie Cai DECLARE_GADGET_BIND_CALLBACK(usb_dnl_rockusb, rockusb_add); 323bf2b72beSEddie Cai 324bf2b72beSEddie Cai static int rockusb_tx_write(const char *buffer, unsigned int buffer_size) 325bf2b72beSEddie Cai { 326bf2b72beSEddie Cai struct usb_request *in_req = rockusb_func->in_req; 327bf2b72beSEddie Cai int ret; 328bf2b72beSEddie Cai 329bf2b72beSEddie Cai memcpy(in_req->buf, buffer, buffer_size); 330bf2b72beSEddie Cai in_req->length = buffer_size; 331e11f9166SAlberto Panizzo debug("Transferring 0x%x bytes\n", buffer_size); 332bf2b72beSEddie Cai usb_ep_dequeue(rockusb_func->in_ep, in_req); 333bf2b72beSEddie Cai ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0); 334bf2b72beSEddie Cai if (ret) 335bf2b72beSEddie Cai printf("Error %d on queue\n", ret); 336bf2b72beSEddie Cai return 0; 337bf2b72beSEddie Cai } 338bf2b72beSEddie Cai 339bf2b72beSEddie Cai static int rockusb_tx_write_str(const char *buffer) 340bf2b72beSEddie Cai { 341bf2b72beSEddie Cai return rockusb_tx_write(buffer, strlen(buffer)); 342bf2b72beSEddie Cai } 343bf2b72beSEddie Cai 344bf2b72beSEddie Cai #ifdef DEBUG 345bf2b72beSEddie Cai static void printcbw(char *buf) 346bf2b72beSEddie Cai { 347bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 348bf2b72beSEddie Cai sizeof(struct fsg_bulk_cb_wrap)); 349bf2b72beSEddie Cai 350bf2b72beSEddie Cai memcpy((char *)cbw, buf, USB_BULK_CB_WRAP_LEN); 351bf2b72beSEddie Cai 352bf2b72beSEddie Cai debug("cbw: signature:%x\n", cbw->signature); 353bf2b72beSEddie Cai debug("cbw: tag=%x\n", cbw->tag); 354bf2b72beSEddie Cai debug("cbw: data_transfer_length=%d\n", cbw->data_transfer_length); 355bf2b72beSEddie Cai debug("cbw: flags=%x\n", cbw->flags); 356bf2b72beSEddie Cai debug("cbw: lun=%d\n", cbw->lun); 357bf2b72beSEddie Cai debug("cbw: length=%d\n", cbw->length); 358bf2b72beSEddie Cai debug("cbw: ucOperCode=%x\n", cbw->CDB[0]); 359bf2b72beSEddie Cai debug("cbw: ucReserved=%x\n", cbw->CDB[1]); 360bf2b72beSEddie Cai debug("cbw: dwAddress:%x %x %x %x\n", cbw->CDB[5], cbw->CDB[4], 361bf2b72beSEddie Cai cbw->CDB[3], cbw->CDB[2]); 362bf2b72beSEddie Cai debug("cbw: ucReserved2=%x\n", cbw->CDB[6]); 363bf2b72beSEddie Cai debug("cbw: uslength:%x %x\n", cbw->CDB[8], cbw->CDB[7]); 364bf2b72beSEddie Cai } 365bf2b72beSEddie Cai 366bf2b72beSEddie Cai static void printcsw(char *buf) 367bf2b72beSEddie Cai { 368bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct bulk_cs_wrap, csw, 369bf2b72beSEddie Cai sizeof(struct bulk_cs_wrap)); 370bf2b72beSEddie Cai memcpy((char *)csw, buf, USB_BULK_CS_WRAP_LEN); 371bf2b72beSEddie Cai debug("csw: signature:%x\n", csw->signature); 372bf2b72beSEddie Cai debug("csw: tag:%x\n", csw->tag); 373bf2b72beSEddie Cai debug("csw: residue:%x\n", csw->residue); 374bf2b72beSEddie Cai debug("csw: status:%x\n", csw->status); 375bf2b72beSEddie Cai } 376bf2b72beSEddie Cai #endif 377bf2b72beSEddie Cai 378bf2b72beSEddie Cai static int rockusb_tx_write_csw(u32 tag, int residue, u8 status, int size) 379bf2b72beSEddie Cai { 380bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct bulk_cs_wrap, csw, 381bf2b72beSEddie Cai sizeof(struct bulk_cs_wrap)); 382bf2b72beSEddie Cai csw->signature = cpu_to_le32(USB_BULK_CS_SIG); 383bf2b72beSEddie Cai csw->tag = tag; 384bf2b72beSEddie Cai csw->residue = cpu_to_be32(residue); 385bf2b72beSEddie Cai csw->status = status; 386bf2b72beSEddie Cai #ifdef DEBUG 387bf2b72beSEddie Cai printcsw((char *)&csw); 388bf2b72beSEddie Cai #endif 389bf2b72beSEddie Cai return rockusb_tx_write((char *)csw, size); 390bf2b72beSEddie Cai } 391bf2b72beSEddie Cai 392cad66e32SAlberto Panizzo static void tx_handler_send_csw(struct usb_ep *ep, struct usb_request *req) 393cad66e32SAlberto Panizzo { 394cad66e32SAlberto Panizzo struct f_rockusb *f_rkusb = get_rkusb(); 395cad66e32SAlberto Panizzo int status = req->status; 396cad66e32SAlberto Panizzo 397cad66e32SAlberto Panizzo if (status) 398cad66e32SAlberto Panizzo debug("status: %d ep '%s' trans: %d\n", 399cad66e32SAlberto Panizzo status, ep->name, req->actual); 400cad66e32SAlberto Panizzo 401cad66e32SAlberto Panizzo /* Return back to default in_req complete function after sending CSW */ 402cad66e32SAlberto Panizzo req->complete = rockusb_complete; 403cad66e32SAlberto Panizzo rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD, USB_BULK_CS_WRAP_LEN); 404cad66e32SAlberto Panizzo } 405cad66e32SAlberto Panizzo 406bf2b72beSEddie Cai static unsigned int rx_bytes_expected(struct usb_ep *ep) 407bf2b72beSEddie Cai { 408bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 409bf2b72beSEddie Cai int rx_remain = f_rkusb->dl_size - f_rkusb->dl_bytes; 410bf2b72beSEddie Cai unsigned int rem; 411bf2b72beSEddie Cai unsigned int maxpacket = ep->maxpacket; 412bf2b72beSEddie Cai 413bf2b72beSEddie Cai if (rx_remain <= 0) 414bf2b72beSEddie Cai return 0; 415bf2b72beSEddie Cai else if (rx_remain > EP_BUFFER_SIZE) 416bf2b72beSEddie Cai return EP_BUFFER_SIZE; 417bf2b72beSEddie Cai 418bf2b72beSEddie Cai rem = rx_remain % maxpacket; 419bf2b72beSEddie Cai if (rem > 0) 420bf2b72beSEddie Cai rx_remain = rx_remain + (maxpacket - rem); 421bf2b72beSEddie Cai 422bf2b72beSEddie Cai return rx_remain; 423bf2b72beSEddie Cai } 424bf2b72beSEddie Cai 425e11f9166SAlberto Panizzo /* usb_request complete call back to handle upload image */ 426e11f9166SAlberto Panizzo static void tx_handler_ul_image(struct usb_ep *ep, struct usb_request *req) 427e11f9166SAlberto Panizzo { 428e11f9166SAlberto Panizzo ALLOC_CACHE_ALIGN_BUFFER(char, rbuffer, RKBLOCK_BUF_SIZE); 429e11f9166SAlberto Panizzo struct f_rockusb *f_rkusb = get_rkusb(); 430e11f9166SAlberto Panizzo struct usb_request *in_req = rockusb_func->in_req; 431e11f9166SAlberto Panizzo int ret; 432e11f9166SAlberto Panizzo 433e11f9166SAlberto Panizzo /* Print error status of previous transfer */ 434e11f9166SAlberto Panizzo if (req->status) 435e11f9166SAlberto Panizzo debug("status: %d ep '%s' trans: %d len %d\n", req->status, 436e11f9166SAlberto Panizzo ep->name, req->actual, req->length); 437e11f9166SAlberto Panizzo 438e11f9166SAlberto Panizzo /* On transfer complete reset in_req and feedback host with CSW_GOOD */ 439e11f9166SAlberto Panizzo if (f_rkusb->ul_bytes >= f_rkusb->ul_size) { 440e11f9166SAlberto Panizzo in_req->length = 0; 441e11f9166SAlberto Panizzo in_req->complete = rockusb_complete; 442e11f9166SAlberto Panizzo 443e11f9166SAlberto Panizzo rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD, 444e11f9166SAlberto Panizzo USB_BULK_CS_WRAP_LEN); 445e11f9166SAlberto Panizzo return; 446e11f9166SAlberto Panizzo } 447e11f9166SAlberto Panizzo 448e11f9166SAlberto Panizzo /* Proceed with current chunk */ 449e11f9166SAlberto Panizzo unsigned int transfer_size = f_rkusb->ul_size - f_rkusb->ul_bytes; 450e11f9166SAlberto Panizzo 451e11f9166SAlberto Panizzo if (transfer_size > RKBLOCK_BUF_SIZE) 452e11f9166SAlberto Panizzo transfer_size = RKBLOCK_BUF_SIZE; 453e11f9166SAlberto Panizzo /* Read at least one block */ 454e11f9166SAlberto Panizzo unsigned int blkcount = (transfer_size + f_rkusb->desc->blksz - 1) / 455e11f9166SAlberto Panizzo f_rkusb->desc->blksz; 456e11f9166SAlberto Panizzo 457e11f9166SAlberto Panizzo debug("ul %x bytes, %x blks, read lba %x, ul_size:%x, ul_bytes:%x, ", 458e11f9166SAlberto Panizzo transfer_size, blkcount, f_rkusb->lba, 459e11f9166SAlberto Panizzo f_rkusb->ul_size, f_rkusb->ul_bytes); 460e11f9166SAlberto Panizzo 461e11f9166SAlberto Panizzo int blks = blk_dread(f_rkusb->desc, f_rkusb->lba, blkcount, rbuffer); 462e11f9166SAlberto Panizzo 463e11f9166SAlberto Panizzo if (blks != blkcount) { 464e11f9166SAlberto Panizzo printf("failed reading from device %s: %d\n", 465e11f9166SAlberto Panizzo f_rkusb->dev_type, f_rkusb->dev_index); 466e11f9166SAlberto Panizzo rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, 467e11f9166SAlberto Panizzo USB_BULK_CS_WRAP_LEN); 468e11f9166SAlberto Panizzo return; 469e11f9166SAlberto Panizzo } 470e11f9166SAlberto Panizzo f_rkusb->lba += blkcount; 471e11f9166SAlberto Panizzo f_rkusb->ul_bytes += transfer_size; 472e11f9166SAlberto Panizzo 473e11f9166SAlberto Panizzo /* Proceed with USB request */ 474e11f9166SAlberto Panizzo memcpy(in_req->buf, rbuffer, transfer_size); 475e11f9166SAlberto Panizzo in_req->length = transfer_size; 476e11f9166SAlberto Panizzo in_req->complete = tx_handler_ul_image; 477*11758a56SAlberto Panizzo debug("Uploading 0x%x bytes\n", transfer_size); 478e11f9166SAlberto Panizzo usb_ep_dequeue(rockusb_func->in_ep, in_req); 479e11f9166SAlberto Panizzo ret = usb_ep_queue(rockusb_func->in_ep, in_req, 0); 480e11f9166SAlberto Panizzo if (ret) 481e11f9166SAlberto Panizzo printf("Error %d on queue\n", ret); 482e11f9166SAlberto Panizzo } 483e11f9166SAlberto Panizzo 484bf2b72beSEddie Cai /* usb_request complete call back to handle down load image */ 485bf2b72beSEddie Cai static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) 486bf2b72beSEddie Cai { 487bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 488bf2b72beSEddie Cai unsigned int transfer_size = 0; 489bf2b72beSEddie Cai const unsigned char *buffer = req->buf; 490bf2b72beSEddie Cai unsigned int buffer_size = req->actual; 491bf2b72beSEddie Cai 492bf2b72beSEddie Cai transfer_size = f_rkusb->dl_size - f_rkusb->dl_bytes; 493bf2b72beSEddie Cai if (!f_rkusb->desc) { 494bf2b72beSEddie Cai char *type = f_rkusb->dev_type; 495bf2b72beSEddie Cai int index = f_rkusb->dev_index; 496bf2b72beSEddie Cai 497bf2b72beSEddie Cai f_rkusb->desc = blk_get_dev(type, index); 498bf2b72beSEddie Cai if (!f_rkusb->desc || 499bf2b72beSEddie Cai f_rkusb->desc->type == DEV_TYPE_UNKNOWN) { 500bf2b72beSEddie Cai puts("invalid mmc device\n"); 501bf2b72beSEddie Cai rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, 502bf2b72beSEddie Cai USB_BULK_CS_WRAP_LEN); 503bf2b72beSEddie Cai return; 504bf2b72beSEddie Cai } 505bf2b72beSEddie Cai } 506bf2b72beSEddie Cai 507bf2b72beSEddie Cai if (req->status != 0) { 508bf2b72beSEddie Cai printf("Bad status: %d\n", req->status); 509bf2b72beSEddie Cai rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, 510bf2b72beSEddie Cai USB_BULK_CS_WRAP_LEN); 511bf2b72beSEddie Cai return; 512bf2b72beSEddie Cai } 513bf2b72beSEddie Cai 514bf2b72beSEddie Cai if (buffer_size < transfer_size) 515bf2b72beSEddie Cai transfer_size = buffer_size; 516bf2b72beSEddie Cai 517bf2b72beSEddie Cai memcpy((void *)f_rkusb->buf, buffer, transfer_size); 518bf2b72beSEddie Cai f_rkusb->dl_bytes += transfer_size; 519bf2b72beSEddie Cai int blks = 0, blkcnt = transfer_size / 512; 520bf2b72beSEddie Cai 521bf2b72beSEddie Cai debug("dl %x bytes, %x blks, write lba %x, dl_size:%x, dl_bytes:%x, ", 522bf2b72beSEddie Cai transfer_size, blkcnt, f_rkusb->lba, f_rkusb->dl_size, 523bf2b72beSEddie Cai f_rkusb->dl_bytes); 524bf2b72beSEddie Cai blks = blk_dwrite(f_rkusb->desc, f_rkusb->lba, blkcnt, f_rkusb->buf); 525bf2b72beSEddie Cai if (blks != blkcnt) { 526bf2b72beSEddie Cai printf("failed writing to device %s: %d\n", f_rkusb->dev_type, 527bf2b72beSEddie Cai f_rkusb->dev_index); 528bf2b72beSEddie Cai rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, 529bf2b72beSEddie Cai USB_BULK_CS_WRAP_LEN); 530bf2b72beSEddie Cai return; 531bf2b72beSEddie Cai } 532bf2b72beSEddie Cai f_rkusb->lba += blkcnt; 533bf2b72beSEddie Cai 534bf2b72beSEddie Cai /* Check if transfer is done */ 535bf2b72beSEddie Cai if (f_rkusb->dl_bytes >= f_rkusb->dl_size) { 536bf2b72beSEddie Cai req->complete = rx_handler_command; 537bf2b72beSEddie Cai req->length = EP_BUFFER_SIZE; 538bf2b72beSEddie Cai f_rkusb->buf = f_rkusb->buf_head; 539*11758a56SAlberto Panizzo debug("transfer 0x%x bytes done\n", f_rkusb->dl_size); 540bf2b72beSEddie Cai f_rkusb->dl_size = 0; 541bf2b72beSEddie Cai rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_GOOD, 542bf2b72beSEddie Cai USB_BULK_CS_WRAP_LEN); 543bf2b72beSEddie Cai } else { 544bf2b72beSEddie Cai req->length = rx_bytes_expected(ep); 545bf2b72beSEddie Cai if (f_rkusb->buf == f_rkusb->buf_head) 546bf2b72beSEddie Cai f_rkusb->buf = f_rkusb->buf_head + EP_BUFFER_SIZE; 547bf2b72beSEddie Cai else 548bf2b72beSEddie Cai f_rkusb->buf = f_rkusb->buf_head; 549bf2b72beSEddie Cai 550bf2b72beSEddie Cai debug("remain %x bytes, %x sectors\n", req->length, 551bf2b72beSEddie Cai req->length / 512); 552bf2b72beSEddie Cai } 553bf2b72beSEddie Cai 554bf2b72beSEddie Cai req->actual = 0; 555bf2b72beSEddie Cai usb_ep_queue(ep, req, 0); 556bf2b72beSEddie Cai } 557bf2b72beSEddie Cai 558bf2b72beSEddie Cai static void cb_test_unit_ready(struct usb_ep *ep, struct usb_request *req) 559bf2b72beSEddie Cai { 560bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 561bf2b72beSEddie Cai sizeof(struct fsg_bulk_cb_wrap)); 562bf2b72beSEddie Cai 563bf2b72beSEddie Cai memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 564bf2b72beSEddie Cai 565bf2b72beSEddie Cai rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, 566bf2b72beSEddie Cai CSW_GOOD, USB_BULK_CS_WRAP_LEN); 567bf2b72beSEddie Cai } 568bf2b72beSEddie Cai 569bf2b72beSEddie Cai static void cb_read_storage_id(struct usb_ep *ep, struct usb_request *req) 570bf2b72beSEddie Cai { 571bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 572bf2b72beSEddie Cai sizeof(struct fsg_bulk_cb_wrap)); 573cad66e32SAlberto Panizzo struct f_rockusb *f_rkusb = get_rkusb(); 574bf2b72beSEddie Cai char emmc_id[] = "EMMC "; 575bf2b72beSEddie Cai 576bf2b72beSEddie Cai printf("read storage id\n"); 577bf2b72beSEddie Cai memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 578cad66e32SAlberto Panizzo 579cad66e32SAlberto Panizzo /* Prepare for sending subsequent CSW_GOOD */ 580cad66e32SAlberto Panizzo f_rkusb->tag = cbw->tag; 581cad66e32SAlberto Panizzo f_rkusb->in_req->complete = tx_handler_send_csw; 582cad66e32SAlberto Panizzo 583bf2b72beSEddie Cai rockusb_tx_write_str(emmc_id); 584bf2b72beSEddie Cai } 585bf2b72beSEddie Cai 586e4b34a76SAlberto Panizzo int __weak rk_get_bootrom_chip_version(unsigned int *chip_info, int size) 587e4b34a76SAlberto Panizzo { 588e4b34a76SAlberto Panizzo return 0; 589e4b34a76SAlberto Panizzo } 590e4b34a76SAlberto Panizzo 591e4b34a76SAlberto Panizzo static void cb_get_chip_version(struct usb_ep *ep, struct usb_request *req) 592e4b34a76SAlberto Panizzo { 593e4b34a76SAlberto Panizzo ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 594e4b34a76SAlberto Panizzo sizeof(struct fsg_bulk_cb_wrap)); 595e4b34a76SAlberto Panizzo struct f_rockusb *f_rkusb = get_rkusb(); 596e4b34a76SAlberto Panizzo unsigned int chip_info[4], i; 597e4b34a76SAlberto Panizzo 598e4b34a76SAlberto Panizzo memset(chip_info, 0, sizeof(chip_info)); 599e4b34a76SAlberto Panizzo rk_get_bootrom_chip_version(chip_info, 4); 600e4b34a76SAlberto Panizzo 601e4b34a76SAlberto Panizzo /* 602e4b34a76SAlberto Panizzo * Chip Version is a string saved in BOOTROM address space Little Endian 603e4b34a76SAlberto Panizzo * 604e4b34a76SAlberto Panizzo * Ex for rk3288: 0x33323041 0x32303134 0x30383133 0x56323030 605e4b34a76SAlberto Panizzo * which brings: 320A20140813V200 606e4b34a76SAlberto Panizzo * 607e4b34a76SAlberto Panizzo * Note that memory version do invert MSB/LSB so printing the char 608e4b34a76SAlberto Panizzo * buffer will show: A02341023180002V 609e4b34a76SAlberto Panizzo */ 610e4b34a76SAlberto Panizzo printf("read chip version: "); 611e4b34a76SAlberto Panizzo for (i = 0; i < 4; i++) { 612e4b34a76SAlberto Panizzo printf("%c%c%c%c", 613e4b34a76SAlberto Panizzo (chip_info[i] >> 24) & 0xFF, 614e4b34a76SAlberto Panizzo (chip_info[i] >> 16) & 0xFF, 615e4b34a76SAlberto Panizzo (chip_info[i] >> 8) & 0xFF, 616e4b34a76SAlberto Panizzo (chip_info[i] >> 0) & 0xFF); 617e4b34a76SAlberto Panizzo } 618e4b34a76SAlberto Panizzo printf("\n"); 619e4b34a76SAlberto Panizzo memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 620e4b34a76SAlberto Panizzo 621e4b34a76SAlberto Panizzo /* Prepare for sending subsequent CSW_GOOD */ 622e4b34a76SAlberto Panizzo f_rkusb->tag = cbw->tag; 623e4b34a76SAlberto Panizzo f_rkusb->in_req->complete = tx_handler_send_csw; 624e4b34a76SAlberto Panizzo 625e4b34a76SAlberto Panizzo rockusb_tx_write((char *)chip_info, sizeof(chip_info)); 626e4b34a76SAlberto Panizzo } 627e4b34a76SAlberto Panizzo 628e11f9166SAlberto Panizzo static void cb_read_lba(struct usb_ep *ep, struct usb_request *req) 629e11f9166SAlberto Panizzo { 630e11f9166SAlberto Panizzo ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 631e11f9166SAlberto Panizzo sizeof(struct fsg_bulk_cb_wrap)); 632e11f9166SAlberto Panizzo struct f_rockusb *f_rkusb = get_rkusb(); 633e11f9166SAlberto Panizzo int sector_count; 634e11f9166SAlberto Panizzo 635e11f9166SAlberto Panizzo memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 636e11f9166SAlberto Panizzo sector_count = (int)get_unaligned_be16(&cbw->CDB[7]); 637e11f9166SAlberto Panizzo f_rkusb->tag = cbw->tag; 638e11f9166SAlberto Panizzo 639e11f9166SAlberto Panizzo if (!f_rkusb->desc) { 640e11f9166SAlberto Panizzo char *type = f_rkusb->dev_type; 641e11f9166SAlberto Panizzo int index = f_rkusb->dev_index; 642e11f9166SAlberto Panizzo 643e11f9166SAlberto Panizzo f_rkusb->desc = blk_get_dev(type, index); 644e11f9166SAlberto Panizzo if (!f_rkusb->desc || 645e11f9166SAlberto Panizzo f_rkusb->desc->type == DEV_TYPE_UNKNOWN) { 646e11f9166SAlberto Panizzo printf("invalid device \"%s\", %d\n", type, index); 647e11f9166SAlberto Panizzo rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, 648e11f9166SAlberto Panizzo USB_BULK_CS_WRAP_LEN); 649e11f9166SAlberto Panizzo return; 650e11f9166SAlberto Panizzo } 651e11f9166SAlberto Panizzo } 652e11f9166SAlberto Panizzo 653e11f9166SAlberto Panizzo f_rkusb->lba = get_unaligned_be32(&cbw->CDB[2]); 654e11f9166SAlberto Panizzo f_rkusb->ul_size = sector_count * f_rkusb->desc->blksz; 655e11f9166SAlberto Panizzo f_rkusb->ul_bytes = 0; 656e11f9166SAlberto Panizzo 657e11f9166SAlberto Panizzo debug("require read %x bytes, %x sectors from lba %x\n", 658e11f9166SAlberto Panizzo f_rkusb->ul_size, sector_count, f_rkusb->lba); 659e11f9166SAlberto Panizzo 660e11f9166SAlberto Panizzo if (f_rkusb->ul_size == 0) { 661e11f9166SAlberto Panizzo rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, 662e11f9166SAlberto Panizzo CSW_FAIL, USB_BULK_CS_WRAP_LEN); 663e11f9166SAlberto Panizzo return; 664e11f9166SAlberto Panizzo } 665e11f9166SAlberto Panizzo 666e11f9166SAlberto Panizzo /* Start right now sending first chunk */ 667e11f9166SAlberto Panizzo tx_handler_ul_image(ep, req); 668e11f9166SAlberto Panizzo } 669e11f9166SAlberto Panizzo 670bf2b72beSEddie Cai static void cb_write_lba(struct usb_ep *ep, struct usb_request *req) 671bf2b72beSEddie Cai { 672bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 673bf2b72beSEddie Cai sizeof(struct fsg_bulk_cb_wrap)); 674bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 675bf2b72beSEddie Cai int sector_count; 676bf2b72beSEddie Cai 677bf2b72beSEddie Cai memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 678bf2b72beSEddie Cai sector_count = (int)get_unaligned_be16(&cbw->CDB[7]); 679bf2b72beSEddie Cai f_rkusb->lba = get_unaligned_be32(&cbw->CDB[2]); 680bf2b72beSEddie Cai f_rkusb->dl_size = sector_count * 512; 681bf2b72beSEddie Cai f_rkusb->dl_bytes = 0; 682bf2b72beSEddie Cai f_rkusb->tag = cbw->tag; 683bf2b72beSEddie Cai debug("require write %x bytes, %x sectors to lba %x\n", 684bf2b72beSEddie Cai f_rkusb->dl_size, sector_count, f_rkusb->lba); 685bf2b72beSEddie Cai 686bf2b72beSEddie Cai if (f_rkusb->dl_size == 0) { 687bf2b72beSEddie Cai rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, 688bf2b72beSEddie Cai CSW_FAIL, USB_BULK_CS_WRAP_LEN); 689bf2b72beSEddie Cai } else { 690bf2b72beSEddie Cai req->complete = rx_handler_dl_image; 691bf2b72beSEddie Cai req->length = rx_bytes_expected(ep); 692bf2b72beSEddie Cai } 693bf2b72beSEddie Cai } 694bf2b72beSEddie Cai 695f68c8e82SAlberto Panizzo static void cb_erase_lba(struct usb_ep *ep, struct usb_request *req) 696f68c8e82SAlberto Panizzo { 697f68c8e82SAlberto Panizzo ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 698f68c8e82SAlberto Panizzo sizeof(struct fsg_bulk_cb_wrap)); 699f68c8e82SAlberto Panizzo struct f_rockusb *f_rkusb = get_rkusb(); 700f68c8e82SAlberto Panizzo int sector_count, lba, blks; 701f68c8e82SAlberto Panizzo 702f68c8e82SAlberto Panizzo memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 703f68c8e82SAlberto Panizzo sector_count = (int)get_unaligned_be16(&cbw->CDB[7]); 704f68c8e82SAlberto Panizzo f_rkusb->tag = cbw->tag; 705f68c8e82SAlberto Panizzo 706f68c8e82SAlberto Panizzo if (!f_rkusb->desc) { 707f68c8e82SAlberto Panizzo char *type = f_rkusb->dev_type; 708f68c8e82SAlberto Panizzo int index = f_rkusb->dev_index; 709f68c8e82SAlberto Panizzo 710f68c8e82SAlberto Panizzo f_rkusb->desc = blk_get_dev(type, index); 711f68c8e82SAlberto Panizzo if (!f_rkusb->desc || 712f68c8e82SAlberto Panizzo f_rkusb->desc->type == DEV_TYPE_UNKNOWN) { 713f68c8e82SAlberto Panizzo printf("invalid device \"%s\", %d\n", type, index); 714f68c8e82SAlberto Panizzo rockusb_tx_write_csw(f_rkusb->tag, 0, CSW_FAIL, 715f68c8e82SAlberto Panizzo USB_BULK_CS_WRAP_LEN); 716f68c8e82SAlberto Panizzo return; 717f68c8e82SAlberto Panizzo } 718f68c8e82SAlberto Panizzo } 719f68c8e82SAlberto Panizzo 720f68c8e82SAlberto Panizzo lba = get_unaligned_be32(&cbw->CDB[2]); 721f68c8e82SAlberto Panizzo 722f68c8e82SAlberto Panizzo debug("require erase %x sectors from lba %x\n", 723f68c8e82SAlberto Panizzo sector_count, lba); 724f68c8e82SAlberto Panizzo 725f68c8e82SAlberto Panizzo blks = blk_derase(f_rkusb->desc, lba, sector_count); 726f68c8e82SAlberto Panizzo if (blks != sector_count) { 727f68c8e82SAlberto Panizzo printf("failed erasing device %s: %d\n", f_rkusb->dev_type, 728f68c8e82SAlberto Panizzo f_rkusb->dev_index); 729f68c8e82SAlberto Panizzo rockusb_tx_write_csw(f_rkusb->tag, 730f68c8e82SAlberto Panizzo cbw->data_transfer_length, CSW_FAIL, 731f68c8e82SAlberto Panizzo USB_BULK_CS_WRAP_LEN); 732f68c8e82SAlberto Panizzo return; 733f68c8e82SAlberto Panizzo } 734f68c8e82SAlberto Panizzo 735f68c8e82SAlberto Panizzo rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, CSW_GOOD, 736f68c8e82SAlberto Panizzo USB_BULK_CS_WRAP_LEN); 737f68c8e82SAlberto Panizzo } 738f68c8e82SAlberto Panizzo 739bf2b72beSEddie Cai void __weak rkusb_set_reboot_flag(int flag) 740bf2b72beSEddie Cai { 741bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 742bf2b72beSEddie Cai 743bf2b72beSEddie Cai printf("rockkusb set reboot flag: %d\n", f_rkusb->reboot_flag); 744bf2b72beSEddie Cai } 745bf2b72beSEddie Cai 746bf2b72beSEddie Cai static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) 747bf2b72beSEddie Cai { 748bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 749bf2b72beSEddie Cai 750bf2b72beSEddie Cai rkusb_set_reboot_flag(f_rkusb->reboot_flag); 751bf2b72beSEddie Cai do_reset(NULL, 0, 0, NULL); 752bf2b72beSEddie Cai } 753bf2b72beSEddie Cai 754bf2b72beSEddie Cai static void cb_reboot(struct usb_ep *ep, struct usb_request *req) 755bf2b72beSEddie Cai { 756bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 757bf2b72beSEddie Cai sizeof(struct fsg_bulk_cb_wrap)); 758bf2b72beSEddie Cai struct f_rockusb *f_rkusb = get_rkusb(); 759bf2b72beSEddie Cai 760bf2b72beSEddie Cai memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 761bf2b72beSEddie Cai f_rkusb->reboot_flag = cbw->CDB[1]; 762bf2b72beSEddie Cai rockusb_func->in_req->complete = compl_do_reset; 763bf2b72beSEddie Cai rockusb_tx_write_csw(cbw->tag, cbw->data_transfer_length, CSW_GOOD, 764bf2b72beSEddie Cai USB_BULK_CS_WRAP_LEN); 765bf2b72beSEddie Cai } 766bf2b72beSEddie Cai 767bf2b72beSEddie Cai static void cb_not_support(struct usb_ep *ep, struct usb_request *req) 768bf2b72beSEddie Cai { 769bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 770bf2b72beSEddie Cai sizeof(struct fsg_bulk_cb_wrap)); 771bf2b72beSEddie Cai 772bf2b72beSEddie Cai memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 773bf2b72beSEddie Cai printf("Rockusb command %x not support yet\n", cbw->CDB[0]); 774bf2b72beSEddie Cai rockusb_tx_write_csw(cbw->tag, 0, CSW_FAIL, USB_BULK_CS_WRAP_LEN); 775bf2b72beSEddie Cai } 776bf2b72beSEddie Cai 777bf2b72beSEddie Cai static const struct cmd_dispatch_info cmd_dispatch_info[] = { 778bf2b72beSEddie Cai { 779bf2b72beSEddie Cai .cmd = K_FW_TEST_UNIT_READY, 780bf2b72beSEddie Cai .cb = cb_test_unit_ready, 781bf2b72beSEddie Cai }, 782bf2b72beSEddie Cai { 783bf2b72beSEddie Cai .cmd = K_FW_READ_FLASH_ID, 784bf2b72beSEddie Cai .cb = cb_read_storage_id, 785bf2b72beSEddie Cai }, 786bf2b72beSEddie Cai { 787bf2b72beSEddie Cai .cmd = K_FW_SET_DEVICE_ID, 788bf2b72beSEddie Cai .cb = cb_not_support, 789bf2b72beSEddie Cai }, 790bf2b72beSEddie Cai { 791bf2b72beSEddie Cai .cmd = K_FW_TEST_BAD_BLOCK, 792bf2b72beSEddie Cai .cb = cb_not_support, 793bf2b72beSEddie Cai }, 794bf2b72beSEddie Cai { 795bf2b72beSEddie Cai .cmd = K_FW_READ_10, 796bf2b72beSEddie Cai .cb = cb_not_support, 797bf2b72beSEddie Cai }, 798bf2b72beSEddie Cai { 799bf2b72beSEddie Cai .cmd = K_FW_WRITE_10, 800bf2b72beSEddie Cai .cb = cb_not_support, 801bf2b72beSEddie Cai }, 802bf2b72beSEddie Cai { 803bf2b72beSEddie Cai .cmd = K_FW_ERASE_10, 804bf2b72beSEddie Cai .cb = cb_not_support, 805bf2b72beSEddie Cai }, 806bf2b72beSEddie Cai { 807bf2b72beSEddie Cai .cmd = K_FW_WRITE_SPARE, 808bf2b72beSEddie Cai .cb = cb_not_support, 809bf2b72beSEddie Cai }, 810bf2b72beSEddie Cai { 811bf2b72beSEddie Cai .cmd = K_FW_READ_SPARE, 812bf2b72beSEddie Cai .cb = cb_not_support, 813bf2b72beSEddie Cai }, 814bf2b72beSEddie Cai { 815bf2b72beSEddie Cai .cmd = K_FW_ERASE_10_FORCE, 816bf2b72beSEddie Cai .cb = cb_not_support, 817bf2b72beSEddie Cai }, 818bf2b72beSEddie Cai { 819bf2b72beSEddie Cai .cmd = K_FW_GET_VERSION, 820bf2b72beSEddie Cai .cb = cb_not_support, 821bf2b72beSEddie Cai }, 822bf2b72beSEddie Cai { 823bf2b72beSEddie Cai .cmd = K_FW_LBA_READ_10, 824e11f9166SAlberto Panizzo .cb = cb_read_lba, 825bf2b72beSEddie Cai }, 826bf2b72beSEddie Cai { 827bf2b72beSEddie Cai .cmd = K_FW_LBA_WRITE_10, 828bf2b72beSEddie Cai .cb = cb_write_lba, 829bf2b72beSEddie Cai }, 830bf2b72beSEddie Cai { 831bf2b72beSEddie Cai .cmd = K_FW_ERASE_SYS_DISK, 832bf2b72beSEddie Cai .cb = cb_not_support, 833bf2b72beSEddie Cai }, 834bf2b72beSEddie Cai { 835bf2b72beSEddie Cai .cmd = K_FW_SDRAM_READ_10, 836bf2b72beSEddie Cai .cb = cb_not_support, 837bf2b72beSEddie Cai }, 838bf2b72beSEddie Cai { 839bf2b72beSEddie Cai .cmd = K_FW_SDRAM_WRITE_10, 840bf2b72beSEddie Cai .cb = cb_not_support, 841bf2b72beSEddie Cai }, 842bf2b72beSEddie Cai { 843bf2b72beSEddie Cai .cmd = K_FW_SDRAM_EXECUTE, 844bf2b72beSEddie Cai .cb = cb_not_support, 845bf2b72beSEddie Cai }, 846bf2b72beSEddie Cai { 847bf2b72beSEddie Cai .cmd = K_FW_READ_FLASH_INFO, 848bf2b72beSEddie Cai .cb = cb_not_support, 849bf2b72beSEddie Cai }, 850bf2b72beSEddie Cai { 851bf2b72beSEddie Cai .cmd = K_FW_GET_CHIP_VER, 852e4b34a76SAlberto Panizzo .cb = cb_get_chip_version, 853bf2b72beSEddie Cai }, 854bf2b72beSEddie Cai { 855bf2b72beSEddie Cai .cmd = K_FW_LOW_FORMAT, 856bf2b72beSEddie Cai .cb = cb_not_support, 857bf2b72beSEddie Cai }, 858bf2b72beSEddie Cai { 859bf2b72beSEddie Cai .cmd = K_FW_SET_RESET_FLAG, 860bf2b72beSEddie Cai .cb = cb_not_support, 861bf2b72beSEddie Cai }, 862bf2b72beSEddie Cai { 863bf2b72beSEddie Cai .cmd = K_FW_SPI_READ_10, 864bf2b72beSEddie Cai .cb = cb_not_support, 865bf2b72beSEddie Cai }, 866bf2b72beSEddie Cai { 867bf2b72beSEddie Cai .cmd = K_FW_SPI_WRITE_10, 868bf2b72beSEddie Cai .cb = cb_not_support, 869bf2b72beSEddie Cai }, 870bf2b72beSEddie Cai { 871f68c8e82SAlberto Panizzo .cmd = K_FW_LBA_ERASE_10, 872f68c8e82SAlberto Panizzo .cb = cb_erase_lba, 873f68c8e82SAlberto Panizzo }, 874f68c8e82SAlberto Panizzo { 875bf2b72beSEddie Cai .cmd = K_FW_SESSION, 876bf2b72beSEddie Cai .cb = cb_not_support, 877bf2b72beSEddie Cai }, 878bf2b72beSEddie Cai { 879bf2b72beSEddie Cai .cmd = K_FW_RESET, 880bf2b72beSEddie Cai .cb = cb_reboot, 881bf2b72beSEddie Cai }, 882bf2b72beSEddie Cai }; 883bf2b72beSEddie Cai 884bf2b72beSEddie Cai static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) 885bf2b72beSEddie Cai { 886bf2b72beSEddie Cai void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; 887bf2b72beSEddie Cai 888bf2b72beSEddie Cai ALLOC_CACHE_ALIGN_BUFFER(struct fsg_bulk_cb_wrap, cbw, 889bf2b72beSEddie Cai sizeof(struct fsg_bulk_cb_wrap)); 890bf2b72beSEddie Cai char *cmdbuf = req->buf; 891bf2b72beSEddie Cai int i; 892bf2b72beSEddie Cai 893bf2b72beSEddie Cai if (req->status || req->length == 0) 894bf2b72beSEddie Cai return; 895bf2b72beSEddie Cai 896bf2b72beSEddie Cai memcpy((char *)cbw, req->buf, USB_BULK_CB_WRAP_LEN); 897bf2b72beSEddie Cai #ifdef DEBUG 898bf2b72beSEddie Cai printcbw(req->buf); 899bf2b72beSEddie Cai #endif 900bf2b72beSEddie Cai 901bf2b72beSEddie Cai for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) { 902bf2b72beSEddie Cai if (cmd_dispatch_info[i].cmd == cbw->CDB[0]) { 903bf2b72beSEddie Cai func_cb = cmd_dispatch_info[i].cb; 904bf2b72beSEddie Cai break; 905bf2b72beSEddie Cai } 906bf2b72beSEddie Cai } 907bf2b72beSEddie Cai 908bf2b72beSEddie Cai if (!func_cb) { 909bf2b72beSEddie Cai printf("unknown command: %s\n", (char *)req->buf); 910bf2b72beSEddie Cai rockusb_tx_write_str("FAILunknown command"); 911bf2b72beSEddie Cai } else { 912bf2b72beSEddie Cai if (req->actual < req->length) { 913bf2b72beSEddie Cai u8 *buf = (u8 *)req->buf; 914bf2b72beSEddie Cai 915bf2b72beSEddie Cai buf[req->actual] = 0; 916bf2b72beSEddie Cai func_cb(ep, req); 917bf2b72beSEddie Cai } else { 918bf2b72beSEddie Cai puts("buffer overflow\n"); 919bf2b72beSEddie Cai rockusb_tx_write_str("FAILbuffer overflow"); 920bf2b72beSEddie Cai } 921bf2b72beSEddie Cai } 922bf2b72beSEddie Cai 923bf2b72beSEddie Cai *cmdbuf = '\0'; 924bf2b72beSEddie Cai req->actual = 0; 925bf2b72beSEddie Cai usb_ep_queue(ep, req, 0); 926bf2b72beSEddie Cai } 927