mirror of
https://github.com/54shady/kernel_drivers_examples.git
synced 2026-01-13 16:02:37 +00:00
1266 lines
37 KiB
C
1266 lines
37 KiB
C
#define IN_FW_Upgrade
|
||
#include <cmd_rockusb.h>
|
||
#include <asm/arch/rkplat.h>
|
||
|
||
#if defined(CONFIG_RK_UDC)
|
||
#include <usb/dwc_otg_udc.h>
|
||
#endif
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
#include <dwc3-uboot.h>
|
||
#include <usb/dwc3_rk_udc.h>
|
||
#endif
|
||
#include <../board/rockchip/common/config.h>
|
||
|
||
DECLARE_GLOBAL_DATA_PTR;
|
||
|
||
#ifdef CONFIG_ROCKUSB_TIMEOUT_CHECK
|
||
static uint64_t TimeOutBase;
|
||
#endif
|
||
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
static void rkusb_init_strings(void);
|
||
|
||
int rkusb_write_bulk_ep(uint32_t nLen, void *buf)
|
||
{
|
||
usbcmd.tx_giveback.status = SEND_IN_PROGRESS;
|
||
usbcmd.tx_giveback.actual = 0;
|
||
usbcmd.tx_giveback.buf = NULL;
|
||
return RK_Dwc3WriteBulkEndpoint(nLen, buf);
|
||
}
|
||
|
||
int rkusb_read_bulk_ep(uint32_t nLen, void *buf)
|
||
{
|
||
usbcmd.rx_giveback.status = RECV_READY;
|
||
usbcmd.rx_giveback.actual = 0;
|
||
usbcmd.rx_giveback.buf = NULL;
|
||
return RK_Dwc3ReadBulkEndpoint(nLen, buf);
|
||
}
|
||
|
||
void rkusb_event_handler_for_dwc3(int nEvent)
|
||
{
|
||
int event = nEvent & 0xffff;
|
||
int param = nEvent>>16;
|
||
RKUSBINFO("@rkusb_event_handler_for_dwc3 %d\n", event);
|
||
switch (event) {
|
||
case 1:/* Device_Reset */
|
||
case 5:/* Device_Disconnect */
|
||
usbcmd.configured = 0;
|
||
break;
|
||
case 2:/* DEVICE_CONFIGURED */
|
||
usbcmd.configured = 1;
|
||
usbcmd.txbuf_num = 0;
|
||
usbcmd.rxbuf_num = 0;
|
||
usbcmd.tx_giveback.status = SEND_FINISHED_OK;
|
||
usbcmd.tx_giveback.actual = 0;
|
||
rkusb_read_bulk_ep(31, usbcmd.rx_buffer[usbcmd.rxbuf_num]);
|
||
usbcmd.rxbuf_num = (usbcmd.rxbuf_num + 1) % 2;
|
||
break;
|
||
case 3:/* DEVICE_ADDRESS_ASSIGNED */
|
||
usbcmd.status = RKUSB_STATUS_IDLE;
|
||
break;
|
||
case 4:/* DEVICE_CLEAR_FEATURE */
|
||
usbcmd.status = RKUSB_STATUS_IDLE;
|
||
/* in ep */
|
||
if (param == 0) {
|
||
usbcmd.txbuf_num = 0;
|
||
usbcmd.tx_giveback.status = SEND_FINISHED_OK;
|
||
usbcmd.tx_giveback.actual = 0;
|
||
}
|
||
/* out ep */
|
||
if (param == 0x1) {
|
||
usbcmd.rxbuf_num = 0;
|
||
rkusb_read_bulk_ep(31, usbcmd.rx_buffer[usbcmd.rxbuf_num]);
|
||
usbcmd.rxbuf_num = (usbcmd.rxbuf_num + 1) % 2;
|
||
}
|
||
/* in and out ep */
|
||
if (param == 0x10) {
|
||
usbcmd.txbuf_num = 0;
|
||
usbcmd.tx_giveback.status = SEND_FINISHED_OK;
|
||
usbcmd.tx_giveback.actual = 0;
|
||
|
||
usbcmd.rxbuf_num = 0;
|
||
rkusb_read_bulk_ep(31, usbcmd.rx_buffer[usbcmd.rxbuf_num]);
|
||
usbcmd.rxbuf_num = (usbcmd.rxbuf_num + 1) % 2;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* usb设备通过该函数获取到对断发送过来的数据 */
|
||
void dwc3_rx_handler(int status, uint32_t actual, void *buf)
|
||
{
|
||
if (status)
|
||
{
|
||
usbcmd.rx_giveback.status = RECV_ERROR;
|
||
}
|
||
else
|
||
{
|
||
usbcmd.rx_giveback.status = RECV_OK;
|
||
usbcmd.rx_giveback.actual = actual;
|
||
usbcmd.rx_giveback.buf = buf;
|
||
}
|
||
}
|
||
|
||
void dwc3_tx_handler(int status, uint32_t actual, void *buf)
|
||
{
|
||
if (status) {
|
||
usbcmd.tx_giveback.status = SEND_FINISHED_ERROR;
|
||
} else {
|
||
usbcmd.tx_giveback.status = SEND_FINISHED_OK;
|
||
usbcmd.tx_giveback.actual = actual;
|
||
usbcmd.tx_giveback.buf = buf;
|
||
}
|
||
}
|
||
|
||
/* 初始化usb实例 */
|
||
void init_dwc3_udc_instance(struct rk_dwc3_udc_instance *instance)
|
||
{
|
||
int i;
|
||
|
||
memset(instance, 0, sizeof(*instance));
|
||
|
||
/* 设置usb设备描述符,配置描述符, 接口描述符 */
|
||
instance->device_desc = &device_descriptor;
|
||
instance->config_desc = (void *)&rkusb_config_desc.configuration_desc;
|
||
instance->interface_desc = &rkusb_config_desc.interface_desc;
|
||
|
||
/*
|
||
* 在board_f.c里设置的地址
|
||
* rx_buffer[0] 保存起始地址
|
||
* rx_buffer[1] 保存结束地址
|
||
* tx_buffer[0] 保存起始地址
|
||
* tx_buffer[1] 保存结束地址
|
||
*
|
||
* rx_buffer[0] --> ------
|
||
* CONFIG_RK_BOOT_BUFFER_SIZE / 2
|
||
* rx_buffer[1] --> ------ <-- tx_buffer[0]
|
||
* CONFIG_RK_BOOT_BUFFER_SIZE / 2
|
||
* rx_buffer[1] --> ------
|
||
*/
|
||
usbcmd.rx_buffer[0] = (u8 *)gd->arch.rk_boot_buf_addr;
|
||
usbcmd.rx_buffer[1] = usbcmd.rx_buffer[0]+(CONFIG_RK_BOOT_BUFFER_SIZE>>2);
|
||
|
||
usbcmd.tx_buffer[0] = (u8 *)gd->arch.rk_boot_buf_addr + (CONFIG_RK_BOOT_BUFFER_SIZE>>1);
|
||
usbcmd.tx_buffer[1] = usbcmd.tx_buffer[0]+(CONFIG_RK_BOOT_BUFFER_SIZE>>2);
|
||
|
||
/* 设置usb设备端点描述符, tx,rx起止地址 */
|
||
for (i = 0; i < 2; i++)
|
||
{
|
||
instance->endpoint_desc[i] = &rkusb_config_desc.endpoint_desc[i];
|
||
instance->rx_buffer[i] = usbcmd.rx_buffer[i];
|
||
instance->tx_buffer[i] = usbcmd.tx_buffer[i];
|
||
}
|
||
|
||
/* 设置usb设备tx,rx大小 */
|
||
instance->rx_buffer_size = CONFIG_RK_BOOT_BUFFER_SIZE>>2;
|
||
instance->tx_buffer_size = CONFIG_RK_BOOT_BUFFER_SIZE>>2;
|
||
|
||
/* 端点0的字符串描述最终保存在usb_strings和rkusb_string_table */
|
||
rkusb_init_strings();
|
||
|
||
/* 设置usb设备的字符串描述 */
|
||
for (i = 0; i < STR_COUNT; i++)
|
||
instance->string_desc[i] = rkusb_string_table[i];
|
||
|
||
/* 事件处理函数 */
|
||
instance->device_event = rkusb_event_handler_for_dwc3;
|
||
instance->rx_handler = dwc3_rx_handler;
|
||
instance->tx_handler = dwc3_tx_handler;
|
||
}
|
||
#endif
|
||
|
||
#ifdef CONFIG_RK_UDC
|
||
/* USB specific */
|
||
void rkusb_receive_firstcbw(void)
|
||
{
|
||
struct usb_endpoint_instance *ep = &endpoint_instance[1];
|
||
/* get first CBW */
|
||
ep->rcv_urb->buffer = (u8 *)&usbcmd.cbw;
|
||
ep->rcv_urb->buffer_length = 31;
|
||
ep->rcv_urb->actual_length = 0;
|
||
/* make sure endpoint will be re-enabled */
|
||
suspend_usb();
|
||
resume_usb(ep, 0);
|
||
}
|
||
|
||
static void rkusb_event_handler (struct usb_device_instance *device,
|
||
usb_device_event_t event, int data)
|
||
{
|
||
RKUSBINFO("@rkusb_event_handler %x\n", event);
|
||
switch (event) {
|
||
case DEVICE_RESET:
|
||
case DEVICE_BUS_INACTIVE:
|
||
usbcmd.configured = 0;
|
||
break;
|
||
case DEVICE_CONFIGURED:
|
||
usbcmd.configured = 1;
|
||
break;
|
||
case DEVICE_ADDRESS_ASSIGNED:
|
||
usbcmd.status = RKUSB_STATUS_IDLE;
|
||
rkusb_init_endpoints();
|
||
rkusb_receive_firstcbw();
|
||
case DEVICE_CLEAR_FEATURE:
|
||
usbcmd.status = RKUSB_STATUS_IDLE;
|
||
endpoint_instance[2].tx_urb->status = SEND_FINISHED_OK;
|
||
endpoint_instance[1].rcv_urb->status = RECV_OK;
|
||
rkusb_receive_firstcbw();
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
/* utility function for converting char* to wide string used by USB */
|
||
static void str2wide(char *str, u16 *wide)
|
||
{
|
||
int i;
|
||
for (i = 0; i < strlen(str) && str[i]; i++) {
|
||
#if defined(__LITTLE_ENDIAN)
|
||
wide[i] = (u16) str[i];
|
||
#elif defined(__BIG_ENDIAN)
|
||
wide[i] = ((u16)(str[i])<<8);
|
||
#else
|
||
#error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined"
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/* 初始化字符描述符 */
|
||
static void rkusb_init_strings(void)
|
||
{
|
||
struct usb_string_descriptor *string;
|
||
|
||
rkusb_string_table[STR_LANG] = (struct usb_string_descriptor *)wstr_lang;
|
||
|
||
string = (struct usb_string_descriptor *)wstr_manufacturer;
|
||
string->bLength = sizeof(wstr_manufacturer);
|
||
string->bDescriptorType = USB_DT_STRING;
|
||
str2wide(CONFIG_USBD_MANUFACTURER, string->wData);
|
||
rkusb_string_table[STR_MANUFACTURER] = string;
|
||
|
||
string = (struct usb_string_descriptor *)wstr_product;
|
||
string->bLength = sizeof(wstr_product);
|
||
string->bDescriptorType = USB_DT_STRING;
|
||
str2wide(CONFIG_USBD_PRODUCT_NAME, string->wData);
|
||
rkusb_string_table[STR_PRODUCT] = string;
|
||
|
||
string = (struct usb_string_descriptor *)wstr_serial;
|
||
string->bLength = sizeof(wstr_serial);
|
||
string->bDescriptorType = USB_DT_STRING;
|
||
str2wide(serial_number, string->wData);
|
||
rkusb_string_table[STR_SERIAL] = string;
|
||
|
||
string = (struct usb_string_descriptor *)wstr_configuration;
|
||
string->bLength = sizeof(wstr_configuration);
|
||
string->bDescriptorType = USB_DT_STRING;
|
||
str2wide(CONFIG_USBD_CONFIGURATION_STR, string->wData);
|
||
rkusb_string_table[STR_CONFIGURATION] = string;
|
||
|
||
string = (struct usb_string_descriptor *)wstr_interface;
|
||
string->bLength = sizeof(wstr_interface);
|
||
string->bDescriptorType = USB_DT_STRING;
|
||
str2wide(CONFIG_USBD_INTERFACE_STR, string->wData);
|
||
rkusb_string_table[STR_INTERFACE] = string;
|
||
|
||
/* 端点0的字符串描述最终保存在usb_strings */
|
||
usb_strings = rkusb_string_table;
|
||
}
|
||
|
||
/* fastboot_init has to be called before this fn to get correct serial string */
|
||
#ifdef CONFIG_RK_UDC
|
||
static void rkusb_init_instances(void)
|
||
{
|
||
int i;
|
||
/* initialize device instance */
|
||
memset((void *)device_instance, 0, sizeof(struct usb_device_instance));
|
||
device_instance->name = rockusb_name;
|
||
device_instance->device_state = STATE_INIT;
|
||
#if defined(CONFIG_RKCHIP_RK3126)
|
||
/* audi-b rockusb product id adjust */
|
||
if (grf_readl(GRF_CHIP_TAG) == 0x3136) {
|
||
device_descriptor.idProduct = cpu_to_le16(0x310D);
|
||
}
|
||
#endif
|
||
device_instance->device_descriptor = &device_descriptor;
|
||
device_instance->bos_descriptor = &rkusb_bos_desc;
|
||
device_instance->event = rkusb_event_handler;
|
||
device_instance->cdc_recv_setup = NULL;
|
||
device_instance->bus = bus_instance;
|
||
device_instance->configurations = NUM_CONFIGS;
|
||
device_instance->configuration_instance_array = config_instance;
|
||
|
||
/* XXX: what is this bus instance for ?, can't it be removed by moving
|
||
endpoint_array and serial_number_str is moved to device instance */
|
||
/* initialize bus instance */
|
||
memset(bus_instance, 0, sizeof(struct usb_bus_instance));
|
||
bus_instance->device = device_instance;
|
||
bus_instance->endpoint_array = endpoint_instance;
|
||
/* XXX: what is the relevance of max_endpoints & maxpacketsize ? */
|
||
bus_instance->max_endpoints = 1;
|
||
bus_instance->maxpacketsize = 64;
|
||
bus_instance->serial_number_str = serial_number;
|
||
|
||
/* configuration instance */
|
||
memset(config_instance, 0, sizeof(struct usb_configuration_instance));
|
||
config_instance->interfaces = NUM_INTERFACES;
|
||
config_instance->configuration_descriptor =
|
||
(struct usb_configuration_descriptor *)&rkusb_config_desc;
|
||
config_instance->interface_instance_array = interface_instance;
|
||
|
||
/* XXX: is alternate instance required in case of no alternate ? */
|
||
/* interface instance */
|
||
memset(interface_instance, 0, sizeof(struct usb_interface_instance));
|
||
interface_instance->alternates = 1;
|
||
interface_instance->alternates_instance_array = alternate_instance;
|
||
|
||
/* alternates instance */
|
||
memset(alternate_instance, 0, sizeof(struct usb_alternate_instance));
|
||
alternate_instance->interface_descriptor = interface_descriptors;
|
||
alternate_instance->endpoints = NUM_ENDPOINTS;
|
||
alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs;
|
||
|
||
/* endpoint instances */
|
||
memset(endpoint_instance, 0, sizeof(endpoint_instance));
|
||
endpoint_instance[0].endpoint_address = 0;
|
||
endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE;
|
||
endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL;
|
||
endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE;
|
||
endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL;
|
||
/* XXX: following statement to done along with other endpoints
|
||
at another place ? */
|
||
#ifdef CONFIG_CMD_FASTBOOT
|
||
usbcmd.rx_buffer[0] = (u8 *)gd->arch.fastboot_buf_addr;
|
||
usbcmd.rx_buffer[1] = usbcmd.rx_buffer[0]+(CONFIG_FASTBOOT_TRANSFER_BUFFER_SIZE_EACH>>1);
|
||
|
||
usbcmd.tx_buffer[0] = (u8 *)gd->arch.fastboot_buf_addr + CONFIG_FASTBOOT_TRANSFER_BUFFER_SIZE_EACH;
|
||
usbcmd.tx_buffer[1] = usbcmd.tx_buffer[0]+(CONFIG_FASTBOOT_TRANSFER_BUFFER_SIZE_EACH>>1);
|
||
#else
|
||
usbcmd.rx_buffer[0] = (u8 *)gd->arch.rk_boot_buf_addr;
|
||
usbcmd.rx_buffer[1] = usbcmd.rx_buffer[0]+(CONFIG_RK_BOOT_BUFFER_SIZE>>2);
|
||
|
||
usbcmd.tx_buffer[0] = (u8 *)gd->arch.rk_boot_buf_addr + (CONFIG_RK_BOOT_BUFFER_SIZE>>1);
|
||
usbcmd.tx_buffer[1] = usbcmd.tx_buffer[0]+(CONFIG_RK_BOOT_BUFFER_SIZE>>2);
|
||
#endif
|
||
RKUSBINFO("%p %p %p %p\n",
|
||
usbcmd.rx_buffer[0], usbcmd.rx_buffer[1], usbcmd.tx_buffer[0], usbcmd.tx_buffer[1]);
|
||
for (i = 1; i <= NUM_ENDPOINTS; i++) {
|
||
endpoint_instance[i].endpoint_address =
|
||
ep_descriptor_ptrs[i - 1]->bEndpointAddress;
|
||
|
||
endpoint_instance[i].rcv_attributes =
|
||
ep_descriptor_ptrs[i - 1]->bmAttributes;
|
||
|
||
endpoint_instance[i].rcv_packetSize =
|
||
le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
|
||
|
||
endpoint_instance[i].tx_attributes =
|
||
ep_descriptor_ptrs[i - 1]->bmAttributes;
|
||
|
||
endpoint_instance[i].tx_packetSize = 0x201;
|
||
|
||
endpoint_instance[i].tx_attributes =
|
||
ep_descriptor_ptrs[i - 1]->bmAttributes;
|
||
|
||
urb_link_init(&endpoint_instance[i].rcv);
|
||
urb_link_init(&endpoint_instance[i].rdy);
|
||
urb_link_init(&endpoint_instance[i].tx);
|
||
urb_link_init(&endpoint_instance[i].done);
|
||
RKUSBINFO("ENDPOINT %d,addr %x\n", i, endpoint_instance[i].endpoint_address);
|
||
if (endpoint_instance[i].endpoint_address & USB_DIR_IN) {
|
||
endpoint_instance[i].tx_urb =
|
||
usbd_alloc_urb(device_instance,
|
||
&endpoint_instance[i]);
|
||
endpoint_instance[i].tx_urb->buffer = usbcmd.tx_buffer[0];
|
||
endpoint_instance[i].tx_urb->status = SEND_FINISHED_OK;
|
||
} else {
|
||
endpoint_instance[i].rcv_urb =
|
||
usbd_alloc_urb(device_instance,
|
||
&endpoint_instance[i]);
|
||
endpoint_instance[i].rcv_urb->buffer = usbcmd.rx_buffer[0];
|
||
endpoint_instance[i].rcv_urb->status = RECV_OK;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* XXX: ep_descriptor_ptrs can be removed by making better use of
|
||
RKUSB_config_desc.endpoint_desc */
|
||
static void rkusb_init_endpoint_ptrs(void)
|
||
{
|
||
ep_descriptor_ptrs[0] = &rkusb_config_desc.endpoint_desc[0];
|
||
ep_descriptor_ptrs[1] = &rkusb_config_desc.endpoint_desc[1];
|
||
}
|
||
|
||
static void rkusb_init_endpoints(void)
|
||
{
|
||
int i;
|
||
|
||
/* XXX: should it be moved to some other function ? */
|
||
bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
|
||
|
||
/* XXX: is this for loop required ?, yes for MUSB it is */
|
||
for (i = 1; i <= NUM_ENDPOINTS; i++) {
|
||
/* configure packetsize based on HS negotiation status */
|
||
if (is_usbd_high_speed()) {
|
||
RKUSBINFO("setting up HS USB device ep%x\n", endpoint_instance[i].endpoint_address);
|
||
ep_descriptor_ptrs[i - 1]->wMaxPacketSize = 0x200;
|
||
} else {
|
||
RKUSBINFO("setting up FS USB device ep%x\n", endpoint_instance[i].endpoint_address);
|
||
ep_descriptor_ptrs[i - 1]->wMaxPacketSize = 0x40;
|
||
}
|
||
/* fastboot will send a zero packet if the last data packet is tx_packetSize, but rockusb don't */
|
||
endpoint_instance[i].tx_packetSize = 0x201;
|
||
endpoint_instance[i].rcv_packetSize = le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/***************************************************************************
|
||
* 命令:测试准备0x00
|
||
***************************************************************************/
|
||
static void FW_TestUnitReady(void)
|
||
{
|
||
if (FW_StorageGetValid() == 0) {
|
||
uint32_t totleBlock = FW_GetTotleBlk();
|
||
uint32_t currEraseBlk = FW_GetCurEraseBlock();
|
||
usbcmd.csw.Residue = cpu_to_be32((totleBlock<<16)|currEraseBlk);
|
||
usbcmd.csw.Status = CSW_FAIL;
|
||
} else if (usbcmd.cbw.CDB[1] == 0xFD) {
|
||
uint32_t totleBlock = FW_GetTotleBlk();
|
||
uint32_t currEraseBlk = 0;
|
||
usbcmd.csw.Residue = cpu_to_be32((totleBlock<<16)|currEraseBlk);
|
||
usbcmd.csw.Status = CSW_FAIL;
|
||
FW_SorageLowFormatEn(1);
|
||
} else if (usbcmd.cbw.CDB[1] == 0xFA) {
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.reset_flag = 0x10;
|
||
} else if (usbcmd.cbw.CDB[1] == 0xF9) {
|
||
usbcmd.csw.Residue = cpu_to_be32(StorageGetCapacity());
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
} else if (SecureBootLock) {
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_FAIL;
|
||
} else {
|
||
usbcmd.csw.Residue = cpu_to_be32(6);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
}
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:固件升级命令:读FLASH ID
|
||
入口参数:无
|
||
出口参数:无
|
||
调用函数:无
|
||
***************************************************************************/
|
||
static void FW_ReadID(void)
|
||
{
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
RKUSBINFO("%s \n", __func__);
|
||
StorageReadId(usbcmd.tx_buffer[usbcmd.txbuf_num]);
|
||
usbcmd.transfer_size = 5;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_TXDATA;
|
||
#else
|
||
struct usb_endpoint_instance *ep = &endpoint_instance[2];
|
||
struct urb *current_urb = NULL;
|
||
|
||
RKUSBINFO("%s \n", __func__);
|
||
|
||
current_urb = ep->tx_urb;
|
||
if (!current_urb) {
|
||
RKUSBERR("%s: current_urb NULL", __func__);
|
||
return;
|
||
}
|
||
|
||
StorageReadId((void *)current_urb->buffer);
|
||
current_urb->actual_length = 5;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_TXDATA;
|
||
#endif
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:固件升级命令:设置FLASH 类型
|
||
Flash 1:
|
||
0:8bit small page; 1:8bit large page 4cyc; 2:8bit large page 5cyc
|
||
3:16bit small page; 4:16bit large page 4cyc; 5:16bit large page 5cyc
|
||
6:MLC 8bit large page 5cyc 7:MLC 8bit large page 5cyc, 4KB/page
|
||
入口参数:
|
||
出口参数:
|
||
调用函数:
|
||
1 2009-4-10 :增加出错返回,PC工具检测到擦除系统盘出错会擦除所有保留块
|
||
后面的块,重启后loader会低格,重新分配空间
|
||
***************************************************************************/
|
||
static void FW_LowFormatSysDisk(void)
|
||
{
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:获取中间件版权信息
|
||
入口参数:无
|
||
出口参数:无
|
||
调用函数:无
|
||
***************************************************************************/
|
||
static void FW_GetChipVer(void)
|
||
{
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
unsigned int chip_info[4];
|
||
RKUSBINFO("%s \n", __func__);
|
||
|
||
memset(chip_info, 0, sizeof(chip_info));
|
||
rk_get_bootrom_chip_version(chip_info);
|
||
|
||
#if defined(CONFIG_RKCHIP_RK3399)
|
||
chip_info[0] = 0x33333043;
|
||
#elif defined(CONFIG_RKCHIP_RK3366)
|
||
chip_info[0] = 0x33333042;
|
||
#endif
|
||
memcpy((uint8_t *)usbcmd.tx_buffer[usbcmd.txbuf_num], (uint8_t *)chip_info, 16);
|
||
usbcmd.transfer_size = 16;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_TXDATA;
|
||
#else
|
||
struct usb_endpoint_instance *ep = &endpoint_instance[2];
|
||
struct urb *current_urb = NULL;
|
||
unsigned int chip_info[4];
|
||
|
||
RKUSBINFO("%s \n", __func__);
|
||
|
||
current_urb = ep->tx_urb;
|
||
if (!current_urb) {
|
||
RKUSBERR("%s: current_urb NULL", __func__);
|
||
return;
|
||
}
|
||
/* notice here chip version should the same as rk tools *.ini config of RKBOOT */
|
||
current_urb->buffer[0] = 0;
|
||
memset(chip_info, 0, sizeof(chip_info));
|
||
rk_get_bootrom_chip_version(chip_info);
|
||
|
||
#if defined(CONFIG_RKCHIP_RK3036)
|
||
chip_info[0] = 0x33303341;
|
||
#elif defined(CONFIG_RKCHIP_RK3126) || defined(CONFIG_RKCHIP_RK3128)
|
||
chip_info[0] = 0x33313241;
|
||
#elif defined(CONFIG_RKCHIP_RK322X)
|
||
chip_info[0] = 0x33323241;
|
||
#elif defined(CONFIG_RKCHIP_RK3366)
|
||
chip_info[0] = 0x33333042;
|
||
#endif
|
||
memcpy((void *)current_urb->buffer, (void *)chip_info, 16);
|
||
current_urb->actual_length = 16;
|
||
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_TXDATA;
|
||
#endif
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:测试坏块——0:好块; 1:坏块
|
||
入口参数:命令块中的指定物理块地址
|
||
出口参数:无
|
||
调用函数:无
|
||
***************************************************************************/
|
||
static void FW_TestBadBlock(void)
|
||
{
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
RKUSBINFO("%s \n", __func__);
|
||
memset((uint8_t *)usbcmd.tx_buffer[usbcmd.txbuf_num], 0, 64);
|
||
usbcmd.transfer_size = 64;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_TXDATA;
|
||
#else
|
||
uint16_t i;
|
||
uint32_t TestResult[16];
|
||
struct usb_endpoint_instance *ep = &endpoint_instance[2];
|
||
struct urb *current_urb = NULL;
|
||
|
||
RKUSBINFO("%s \n", __func__);
|
||
current_urb = ep->tx_urb;
|
||
for (i = 0; i < 16; i++)
|
||
TestResult[i] = 0;
|
||
memcpy((void *)current_urb->buffer, (void *)TestResult, 64);
|
||
current_urb->actual_length = 64;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_TXDATA;
|
||
#endif
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:按528 PAGE大小读
|
||
入口参数:命令块中的物理行地址及传输扇区数
|
||
出口参数:无
|
||
调用函数:无
|
||
***************************************************************************/
|
||
static void FW_Read10(void)
|
||
{
|
||
usbcmd.u_size = get_unaligned_be16(&usbcmd.cbw.CDB[NSECTORS_IN_CDB_INDEX]) * 528;
|
||
usbcmd.u_bytes = 0;
|
||
usbcmd.lba = get_unaligned_be32(&usbcmd.cbw.CDB[OFFSET_IN_CDB_INDEX]);
|
||
usbcmd.status = RKUSB_STATUS_TXDATA_PREPARE;
|
||
}
|
||
|
||
static void FW_Write10(void)
|
||
{
|
||
uint32_t rxdata_blocks = 0;
|
||
|
||
/* 从usb通行命令中取出得到的数据传输大小信息 */
|
||
usbcmd.d_size = get_unaligned_be16(&usbcmd.cbw.CDB[NSECTORS_IN_CDB_INDEX]) * 528;
|
||
usbcmd.d_bytes = 0;
|
||
usbcmd.lba = get_unaligned_be32(&usbcmd.cbw.CDB[OFFSET_IN_CDB_INDEX]);
|
||
|
||
RKUSBINFO("WRITE10 %x len %x\n", usbcmd.lba, usbcmd.d_size);
|
||
|
||
/* check current lba buffer not include in pre lba buffer */
|
||
rxdata_blocks = usbcmd.d_size/528;
|
||
if (!(((usbcmd.lba + rxdata_blocks) < usbcmd.pre_read.pre_lba)
|
||
|| (usbcmd.lba > (usbcmd.pre_read.pre_lba + usbcmd.pre_read.pre_blocks)))) {
|
||
RKUSBINFO("FW_Write10: invalid pre read\n");
|
||
usbcmd.pre_read.pre_blocks = 0;
|
||
usbcmd.pre_read.pre_lba = 0;
|
||
}
|
||
usbcmd.rx_giveback.actual = 0;
|
||
usbcmd.status = RKUSB_STATUS_RXDATA_PREPARE;
|
||
}
|
||
|
||
|
||
/***************************************************************************
|
||
函数描述:按物理BLOCK擦除——0:好块; 1:坏块
|
||
入口参数:命令块中的物理块地址
|
||
出口参数:无
|
||
调用函数:无
|
||
***************************************************************************/
|
||
static void FW_Erase10(void)
|
||
{
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
RKUSBINFO("%s \n", __func__);
|
||
int status = 0;
|
||
if (SecureBootLock == 0) {
|
||
status = StorageEraseBlock(get_unaligned_be32(&usbcmd.cbw.CDB[OFFSET_IN_CDB_INDEX]), get_unaligned_be16(&usbcmd.cbw.CDB[NSECTORS_IN_CDB_INDEX]), 0);
|
||
}
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = (status == 0) ? 0 : 1;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
#else
|
||
bool status = 0;
|
||
struct usb_endpoint_instance *ep = &endpoint_instance[2];
|
||
struct urb *current_urb = NULL;
|
||
|
||
RKUSBINFO("%s \n", __func__);
|
||
current_urb = ep->tx_urb;
|
||
|
||
if (SecureBootLock == 0) {
|
||
StorageEraseBlock(get_unaligned_be32(&usbcmd.cbw.CDB[OFFSET_IN_CDB_INDEX]), get_unaligned_be16(&usbcmd.cbw.CDB[NSECTORS_IN_CDB_INDEX]), 0);
|
||
}
|
||
current_urb->actual_length = 13;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = status;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
#endif
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:按物理BLOCK擦除——0:好块; 1:坏块
|
||
入口参数:命令块中的物理块地址
|
||
出口参数:无
|
||
调用函数:无
|
||
***************************************************************************/
|
||
static void FW_Erase10Force(void)
|
||
{
|
||
int status = 0;
|
||
if (SecureBootLock == 0) {
|
||
status = StorageEraseBlock(get_unaligned_be32(&usbcmd.cbw.CDB[OFFSET_IN_CDB_INDEX]), get_unaligned_be16(&usbcmd.cbw.CDB[NSECTORS_IN_CDB_INDEX]), 1);
|
||
}
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = (status == 0) ? 0 : 1;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
}
|
||
|
||
static void FW_LBARead10(void)
|
||
{
|
||
usbcmd.u_size = get_unaligned_be16(&usbcmd.cbw.CDB[NSECTORS_IN_CDB_INDEX]) * 512;
|
||
usbcmd.u_bytes = 0;
|
||
usbcmd.lba = get_unaligned_be32(&usbcmd.cbw.CDB[2]);
|
||
usbcmd.status = RKUSB_STATUS_TXDATA_PREPARE;
|
||
RKUSBINFO("LBA_READ %x len %x\n", usbcmd.lba, usbcmd.u_size);
|
||
}
|
||
|
||
static void FW_LBAWrite10(void)
|
||
{
|
||
uint32_t rxdata_blocks = 0;
|
||
|
||
usbcmd.d_size = get_unaligned_be16(&usbcmd.cbw.CDB[NSECTORS_IN_CDB_INDEX]) * 512;
|
||
usbcmd.d_bytes = 0;
|
||
usbcmd.lba = get_unaligned_be32(&usbcmd.cbw.CDB[OFFSET_IN_CDB_INDEX]);
|
||
usbcmd.imgwr_mode = usbcmd.cbw.CDB[1];
|
||
RKUSBINFO("LBA_WRITE %x len %x\n", usbcmd.lba, usbcmd.d_size);
|
||
/* check current lba buffer not include in pre lba buffer */
|
||
rxdata_blocks = usbcmd.d_size/512;
|
||
if (!(((usbcmd.lba + rxdata_blocks) < usbcmd.pre_read.pre_lba)
|
||
|| (usbcmd.lba > (usbcmd.pre_read.pre_lba + usbcmd.pre_read.pre_blocks)))) {
|
||
RKUSBINFO("FW_LBAWrite10: invalid pre read\n");
|
||
usbcmd.pre_read.pre_blocks = 0;
|
||
usbcmd.pre_read.pre_lba = 0;
|
||
}
|
||
usbcmd.rx_giveback.actual = 0;
|
||
usbcmd.status = RKUSB_STATUS_RXDATA_PREPARE;
|
||
}
|
||
|
||
static void FW_GetFlashInfo(void)
|
||
{
|
||
StorageReadFlashInfo(usbcmd.tx_buffer[usbcmd.txbuf_num]);
|
||
|
||
usbcmd.transfer_size = 11;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_TXDATA;
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:按物理BLOCK擦除——0:好块; 1:坏块
|
||
入口参数:命令块中的物理块地址
|
||
出口参数:无
|
||
调用函数:无
|
||
***************************************************************************/
|
||
static void FW_LowFormat(void)
|
||
{
|
||
RKUSBINFO("%s \n", __func__);
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
|
||
FW_SorageLowFormatEn(1);
|
||
}
|
||
|
||
static void FW_SetResetFlag(void)
|
||
{
|
||
RKUSBINFO("%s \n", __func__);
|
||
usbcmd.reset_flag = 1;
|
||
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
}
|
||
|
||
/***************************************************************************
|
||
函数描述:系统复位
|
||
入口参数:无
|
||
出口参数:无
|
||
调用函数:无
|
||
LOG:
|
||
20100209,HSL@RK,ADD LUN for deffirent reboot.
|
||
0: normal reboot, 1: loader reboot.
|
||
***************************************************************************/
|
||
static void FW_Reset(void)
|
||
{
|
||
RKUSBINFO("%x \n", usbcmd.cbw.CDB[1]);
|
||
|
||
if (usbcmd.cbw.CDB[1])
|
||
usbcmd.reset_flag = usbcmd.cbw.CDB[1];
|
||
else
|
||
usbcmd.reset_flag = 0xff;
|
||
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
}
|
||
|
||
static int rkusb_send_csw(void)
|
||
{
|
||
struct bulk_cs_wrap *csw = &usbcmd.csw;
|
||
RKUSBINFO("%s tag %x\n", __func__, usbcmd.cbw.Tag);
|
||
|
||
if (usbcmd.tx_giveback.status != SEND_FINISHED_OK)
|
||
return -EBUSY;
|
||
|
||
csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
|
||
csw->Tag = usbcmd.cbw.Tag;
|
||
memcpy(usbcmd.tx_buffer[usbcmd.txbuf_num], (u8 *)&usbcmd.csw, 13);
|
||
rkusb_write_bulk_ep(13, usbcmd.tx_buffer[usbcmd.txbuf_num]);
|
||
usbcmd.txbuf_num = (usbcmd.txbuf_num + 1) % 2;
|
||
rkusb_read_bulk_ep(31, usbcmd.rx_buffer[usbcmd.rxbuf_num]);
|
||
usbcmd.rxbuf_num = (usbcmd.rxbuf_num + 1) % 2;
|
||
|
||
usbcmd.status = RKUSB_STATUS_IDLE;
|
||
|
||
return 0;
|
||
}
|
||
|
||
void do_rockusb_cmd(void)
|
||
{
|
||
/* 当usb设备从总线上拿到数据后保存在rx_giveback.buf里 */
|
||
memcpy(&usbcmd.cbw, usbcmd.rx_giveback.buf, sizeof(usbcmd.cbw));
|
||
|
||
/* 获取到cdb */
|
||
usbcmd.cmnd = usbcmd.cbw.CDB[0];
|
||
//printf("CBW Tag: %x Flags: %x Length : %x CDB[0] : %x\n", usbcmd.cbw.Tag, usbcmd.cbw.Flags, usbcmd.cbw.Length, usbcmd.cmnd);
|
||
|
||
switch (usbcmd.cmnd) {
|
||
case K_FW_TEST_UNIT_READY:
|
||
FW_TestUnitReady();
|
||
break;
|
||
case K_FW_READ_FLASH_ID:
|
||
FW_ReadID();
|
||
break;
|
||
case K_FW_TEST_BAD_BLOCK:
|
||
FW_TestBadBlock();
|
||
break;
|
||
case K_FW_READ_10:
|
||
FW_Read10();
|
||
break;
|
||
case K_FW_WRITE_10:
|
||
FW_Write10();
|
||
break;
|
||
case K_FW_ERASE_10:
|
||
FW_Erase10();
|
||
break;
|
||
case K_FW_ERASE_10_FORCE:
|
||
FW_Erase10Force();
|
||
break;
|
||
case K_FW_LBA_READ_10:
|
||
FW_LBARead10();
|
||
break;
|
||
case K_FW_LBA_WRITE_10:
|
||
FW_LBAWrite10();
|
||
break;
|
||
case K_FW_ERASE_SYS_DISK:
|
||
FW_LowFormatSysDisk();
|
||
break;
|
||
case K_FW_READ_FLASH_INFO:
|
||
FW_GetFlashInfo();
|
||
break;
|
||
case K_FW_GET_CHIP_VER:
|
||
FW_GetChipVer();
|
||
break;
|
||
case K_FW_LOW_FORMAT:
|
||
FW_LowFormat();
|
||
break;
|
||
case K_FW_SET_RESET_FLAG:
|
||
FW_SetResetFlag();
|
||
break;
|
||
case K_FW_RESET:
|
||
FW_Reset();
|
||
break;
|
||
default:
|
||
printf("Unknow command\n");
|
||
break;
|
||
}
|
||
}
|
||
|
||
void rkusb_handle_datarx(void)
|
||
{
|
||
uint8_t *rxdata_buf = NULL;
|
||
uint32_t rxdata_blocks = 0;
|
||
uint32_t transfer_length;
|
||
uint32_t rx_blocks = 0;
|
||
uint32_t block_length ;
|
||
int iRet;
|
||
|
||
/* 每次传输的大小 */
|
||
if (usbcmd.cmnd == K_FW_WRITE_10)
|
||
block_length = 528;
|
||
else if (usbcmd.cmnd == K_FW_LBA_WRITE_10)
|
||
block_length = 512;
|
||
else
|
||
block_length = 512;
|
||
|
||
/* 实际收到数据的长度 */
|
||
if (usbcmd.rx_giveback.actual)
|
||
{
|
||
usbcmd.d_bytes += usbcmd.rx_giveback.actual;
|
||
rxdata_buf = (uint8_t *)usbcmd.rx_giveback.buf;
|
||
rxdata_blocks = usbcmd.rx_giveback.actual / block_length;
|
||
}
|
||
|
||
/* 实际收到数据长度比理论值小,说明还有数据没传输过来,继续读取数据 */
|
||
if (usbcmd.d_bytes < usbcmd.d_size)
|
||
{
|
||
/* 还需要传输的数据长度 */
|
||
transfer_length = usbcmd.d_size - usbcmd.d_bytes;
|
||
|
||
rx_blocks = transfer_length / block_length;
|
||
if (rx_blocks > RKUSB_BUFFER_BLOCK_MAX)
|
||
rx_blocks = RKUSB_BUFFER_BLOCK_MAX;
|
||
|
||
transfer_length = rx_blocks * block_length;
|
||
|
||
/* 再次读取剩余的数据 */
|
||
rkusb_read_bulk_ep(transfer_length, usbcmd.rx_buffer[usbcmd.rxbuf_num]);
|
||
|
||
usbcmd.rxbuf_num = (usbcmd.rxbuf_num + 1) % 2;
|
||
usbcmd.status = RKUSB_STATUS_RXDATA;
|
||
}
|
||
else
|
||
{
|
||
/* 数据传输完毕,发送csw给主机 */
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
rkusb_send_csw();
|
||
}
|
||
|
||
/* 将接收到的数据按块写入存储介质中 */
|
||
if (rxdata_blocks)
|
||
{
|
||
RKUSBINFO("write to media %x, lba %x, buf %p\n", rxdata_blocks, usbcmd.lba, rxdata_buf);
|
||
if (usbcmd.cmnd == K_FW_WRITE_10)
|
||
{
|
||
ISetLoaderFlag(SYS_LOADER_ERR_FLAG);
|
||
if (SecureBootLock == 0)
|
||
{
|
||
iRet = StorageWritePba(usbcmd.lba, rxdata_buf, rxdata_blocks);
|
||
usbcmd.lba += rxdata_blocks;
|
||
if (iRet != FTL_OK)
|
||
RKUSBERR("StorageWritePba failed,err=%d\n", iRet);
|
||
}
|
||
}
|
||
else if (usbcmd.cmnd == K_FW_LBA_WRITE_10)
|
||
{
|
||
if (usbcmd.lba >= 0xFFFFFF00)
|
||
{
|
||
StorageVendorSysDataStore(usbcmd.lba - 0xFFFFFF00, rxdata_blocks, (uint32 *)rxdata_buf);
|
||
usbcmd.lba += rxdata_blocks;
|
||
}
|
||
else if (usbcmd.lba == 0xFFFFF000)
|
||
{
|
||
SecureBootUnlock(rxdata_buf);
|
||
}
|
||
else if ((usbcmd.lba & 0xFFFF0000) == 0xFFF00000)
|
||
{
|
||
iRet = vendor_storage_write(*(uint16 *)rxdata_buf, rxdata_buf+8, *(uint16 *)(rxdata_buf+4));
|
||
if (iRet == -1) {
|
||
RKUSBERR("vendor_storage_write failed,err=%d\n", iRet);
|
||
}
|
||
usbcmd.lba += rxdata_blocks;
|
||
}
|
||
else if (SecureBootLock == 0)
|
||
{
|
||
iRet = StorageWriteLba(usbcmd.lba, rxdata_buf, rxdata_blocks, usbcmd.imgwr_mode);
|
||
if (iRet != FTL_OK)
|
||
RKUSBERR("StorageWriteLba failed,err=%d\n", iRet);
|
||
|
||
usbcmd.lba += rxdata_blocks;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void rkusb_handle_datatx(void)
|
||
{
|
||
uint32_t txdata_size = 0;
|
||
uint32_t tx_blocks = 0;
|
||
uint32_t block_length = 0;
|
||
uint32_t pre_blocks = 0;
|
||
int iRet;
|
||
|
||
start:
|
||
pre_blocks = 0;
|
||
txdata_size = usbcmd.u_size - usbcmd.u_bytes;
|
||
|
||
if (usbcmd.cmnd == K_FW_READ_10)
|
||
block_length = 528;
|
||
else if (usbcmd.cmnd == K_FW_LBA_READ_10)
|
||
block_length = 512;
|
||
|
||
tx_blocks = txdata_size / block_length;
|
||
if (tx_blocks >= RKUSB_BUFFER_BLOCK_MAX) {
|
||
tx_blocks = RKUSB_BUFFER_BLOCK_MAX;
|
||
txdata_size = tx_blocks * block_length;
|
||
}
|
||
|
||
if (tx_blocks
|
||
&& (usbcmd.pre_read.pre_blocks >= tx_blocks)
|
||
&& (usbcmd.pre_read.pre_lba == usbcmd.lba)) {
|
||
|
||
usbcmd.u_bytes += txdata_size;
|
||
usbcmd.lba += tx_blocks;
|
||
usbcmd.pre_read.pre_blocks -= tx_blocks;
|
||
RKUSBINFO("rkusb_write_bulk_ep buffer %p, len %x\n", usbcmd.tx_buffer[usbcmd.txbuf_num], txdata_size);
|
||
rkusb_write_bulk_ep(txdata_size, usbcmd.tx_buffer[usbcmd.txbuf_num]);
|
||
usbcmd.txbuf_num = (usbcmd.txbuf_num + 1) % 2;
|
||
}
|
||
|
||
if (usbcmd.u_size == usbcmd.u_bytes) {
|
||
pre_blocks = 0;
|
||
/* clear pre_read data */
|
||
usbcmd.pre_read.pre_lba = 0;
|
||
usbcmd.pre_read.pre_blocks = 0;
|
||
} else if ((usbcmd.u_bytes == 0) || (tx_blocks == RKUSB_BUFFER_BLOCK_MAX)) {
|
||
RKUSBINFO("read u_bytes %x, tx_blocks %x\n", usbcmd.u_bytes, tx_blocks);
|
||
pre_blocks = tx_blocks;
|
||
usbcmd.pre_read.pre_buffer = usbcmd.tx_buffer[usbcmd.txbuf_num];
|
||
usbcmd.pre_read.pre_lba = usbcmd.lba;
|
||
usbcmd.pre_read.pre_blocks = tx_blocks;
|
||
}
|
||
/* read data from media */
|
||
if (pre_blocks) {
|
||
RKUSBINFO("read lba %x, buffer %p block %x\n", usbcmd.pre_read.pre_lba, usbcmd.pre_read.pre_buffer, pre_blocks);
|
||
memset(usbcmd.pre_read.pre_buffer, 0, pre_blocks * block_length);
|
||
if (usbcmd.cmnd == K_FW_READ_10) {
|
||
iRet = StorageReadPba(usbcmd.pre_read.pre_lba, usbcmd.pre_read.pre_buffer, pre_blocks);
|
||
if (iRet != FTL_OK) {
|
||
RKUSBERR("StorageReadPba failed,err=%d\n", iRet);
|
||
}
|
||
} else if (usbcmd.cmnd == K_FW_LBA_READ_10) {
|
||
if (usbcmd.lba >= 0xFFFFFF00)
|
||
StorageVendorSysDataLoad(usbcmd.pre_read.pre_lba - 0xFFFFFF00, pre_blocks, (uint32 *)usbcmd.pre_read.pre_buffer);
|
||
else if (usbcmd.lba == 0xFFFFF000)
|
||
SecureBootUnlockCheck(usbcmd.pre_read.pre_buffer);
|
||
else if ((usbcmd.lba & 0xFFFF0000) == 0xFFF00000) {
|
||
uint16_t req_id = (usbcmd.lba & 0xFFFF);
|
||
uint8 *p_buf = usbcmd.pre_read.pre_buffer;
|
||
iRet = vendor_storage_read(req_id, p_buf + 8, usbcmd.u_size - 8);
|
||
if (iRet == -1) {
|
||
RKUSBERR("vendor_storage_read failed,err=%d\n", iRet);
|
||
} else {
|
||
p_buf[0] = (uint32_t)(req_id & 0xFF);
|
||
p_buf[1] = (uint32_t)((req_id >> 8) & 0xFF);
|
||
p_buf[4] = (uint32_t)(iRet & 0xFF);
|
||
p_buf[5] = (uint32_t)((iRet >> 8) & 0xFF);
|
||
}
|
||
} else {
|
||
iRet = StorageReadLba(usbcmd.pre_read.pre_lba, usbcmd.pre_read.pre_buffer, pre_blocks);
|
||
if (iRet != FTL_OK) {
|
||
RKUSBERR("StorageReadLba failed,err=%d\n", iRet);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (usbcmd.u_bytes == 0)
|
||
goto start;
|
||
|
||
if (usbcmd.u_size == usbcmd.u_bytes) {
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
}
|
||
}
|
||
|
||
static void rkusb_handle_response(void)
|
||
{
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
switch (usbcmd.status) {
|
||
case RKUSB_STATUS_TXDATA:
|
||
RKUSBINFO("rkusb_write_bulk_ep %x\n", usbcmd.transfer_size);
|
||
rkusb_write_bulk_ep(usbcmd.transfer_size, usbcmd.tx_buffer[usbcmd.txbuf_num]);
|
||
usbcmd.txbuf_num = (usbcmd.txbuf_num + 1) % 2;
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
break;
|
||
case RKUSB_STATUS_RXDATA:
|
||
if (usbcmd.rx_giveback.status == RECV_OK)
|
||
rkusb_handle_datarx();
|
||
break;
|
||
|
||
case RKUSB_STATUS_RXDATA_PREPARE:
|
||
rkusb_handle_datarx();
|
||
break;
|
||
|
||
case RKUSB_STATUS_TXDATA_PREPARE:
|
||
if ((usbcmd.u_bytes == 0) || (usbcmd.tx_giveback.status == SEND_FINISHED_OK))
|
||
rkusb_handle_datatx();
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
#else
|
||
struct usb_endpoint_instance *ep;
|
||
struct urb *current_urb = NULL;
|
||
uint32_t actural_length;
|
||
|
||
switch (usbcmd.status) {
|
||
case RKUSB_STATUS_TXDATA:
|
||
ep = &endpoint_instance[2];
|
||
current_urb = ep->tx_urb;
|
||
udc_endpoint_write(ep);
|
||
usbcmd.data_size = 0;
|
||
RKUSBINFO("udc_endpoint_write %x\n", current_urb->actual_length);
|
||
if (usbcmd.data_size == 0) {
|
||
usbcmd.csw.Residue = cpu_to_be32(usbcmd.cbw.DataTransferLength);
|
||
usbcmd.csw.Status = CSW_GOOD;
|
||
usbcmd.status = RKUSB_STATUS_CSW;
|
||
}
|
||
break;
|
||
|
||
case RKUSB_STATUS_RXDATA:
|
||
ep = &endpoint_instance[1];
|
||
current_urb = ep->rcv_urb;
|
||
actural_length = current_urb->actual_length;
|
||
if (actural_length)
|
||
rkusb_handle_datarx();
|
||
break;
|
||
|
||
case RKUSB_STATUS_RXDATA_PREPARE:
|
||
rkusb_handle_datarx();
|
||
break;
|
||
case RKUSB_STATUS_TXDATA_PREPARE:
|
||
ep = &endpoint_instance[2];
|
||
current_urb = ep->tx_urb;
|
||
if ((usbcmd.u_bytes == 0) || (current_urb->status == SEND_FINISHED_OK))
|
||
rkusb_handle_datatx();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
static int rkusb_timeout_check(int flag)
|
||
{
|
||
#ifdef CONFIG_RK_DWC3_UDC
|
||
if (flag) {
|
||
if (GetVbus()) {
|
||
if (!usbcmd.configured) {
|
||
if (get_timer(TimeOutBase) > (10*1000)) {
|
||
printf("Usb Timeout, Return for boot recovery!\n");
|
||
return 1;
|
||
}
|
||
}
|
||
} else {
|
||
TimeOutBase = get_ticks();
|
||
}
|
||
}
|
||
return 0;
|
||
#else
|
||
/* TV Box: usb default as host, so Vbus always is high,
|
||
* if recovery key pressed and not connect to pc,
|
||
* 10s timeout enter recovery.
|
||
*/
|
||
if (flag) {
|
||
if (GetVbus()) {
|
||
if (!UsbConnectStatus()) {
|
||
if (get_timer(TimeOutBase) > (10*1000)) {
|
||
printf("Usb Timeout, Return for boot recovery!\n");
|
||
return 1;
|
||
}
|
||
}
|
||
} else {
|
||
TimeOutBase = get_ticks();
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
|
||
static void rkusb_reset_check(void)
|
||
{
|
||
if (usbcmd.reset_flag == 0x03) {
|
||
/* reboot to maskrom */
|
||
usbcmd.reset_flag = 0;
|
||
ISetLoaderFlag(0xEF08A53C);
|
||
mdelay(10);
|
||
reset_cpu(0);
|
||
} else if (usbcmd.reset_flag == 0x10) {
|
||
/* lock loader */
|
||
usbcmd.reset_flag = 0;
|
||
SecureBootLockLoader();
|
||
|
||
} else if (usbcmd.reset_flag == 0xFF) {
|
||
/* reboot */
|
||
usbcmd.reset_flag = 0;
|
||
mdelay(10);
|
||
reset_cpu(0);
|
||
} else if (usbcmd.reset_flag == 0x01) {
|
||
/* force to reboot to system, no check loader mode */
|
||
usbcmd.reset_flag = 0;
|
||
ISetLoaderFlag(SYS_LOADER_REBOOT_FLAG | BOOT_NORECOVER);
|
||
mdelay(10);
|
||
reset_cpu(0);
|
||
}
|
||
}
|
||
|
||
static void rkusb_lowformat_check(void)
|
||
{
|
||
FW_SorageLowFormat();
|
||
}
|
||
|
||
|
||
int do_rockusb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||
{
|
||
|
||
/* usb实例,表示一个usb设备 */
|
||
struct rk_dwc3_udc_instance instance;
|
||
int ret;
|
||
|
||
RKUSBINFO("<<Dwc3>> do_rockusb come in.\n");
|
||
memset(&usbcmd, 0, sizeof(struct cmd_rockusb_interface));
|
||
|
||
/* 初始化usb实例 */
|
||
init_dwc3_udc_instance(&instance);
|
||
|
||
/* 将usb实例关联到global_rk_instance */
|
||
rk_dwc3_startup(&instance);
|
||
|
||
/* 打开usb连接 */
|
||
ret = rk_dwc3_connect();
|
||
if (ret) {
|
||
RKUSBINFO("<<Dwc3>> rk_dwc3_connect failed.\n");
|
||
goto Exit_DoRockusb;
|
||
}
|
||
#ifdef CONFIG_ROCKUSB_TIMEOUT_CHECK
|
||
TimeOutBase = get_ticks();
|
||
#endif
|
||
while (1)
|
||
{
|
||
/* 在通信过程中有中断则处理中断 */
|
||
dwc3_uboot_handle_interrupt();
|
||
|
||
/* usb总线没有数据传输的时候就是idle状态 */
|
||
if (usbcmd.status == RKUSB_STATUS_IDLE)
|
||
{
|
||
/* 当总线上有接收到数据时
|
||
* 按照通信双方约定
|
||
* 先传输命令,根据命令执行相应操作
|
||
* 所以这里解析命令
|
||
*
|
||
* 当收到对端数据后dwc3_rx_handler进行数据接收
|
||
*/
|
||
if (usbcmd.rx_giveback.actual > 0)
|
||
{
|
||
usbcmd.status = RKUSB_STATUS_CMD;
|
||
do_rockusb_cmd();
|
||
}
|
||
}
|
||
|
||
if (usbcmd.status == RKUSB_STATUS_RXDATA ||
|
||
usbcmd.status == RKUSB_STATUS_TXDATA ||
|
||
usbcmd.status == RKUSB_STATUS_RXDATA_PREPARE ||
|
||
usbcmd.status == RKUSB_STATUS_TXDATA_PREPARE)
|
||
{
|
||
rkusb_handle_response();
|
||
}
|
||
|
||
if (usbcmd.status == RKUSB_STATUS_CSW)
|
||
{
|
||
rkusb_send_csw();
|
||
}
|
||
|
||
rkusb_reset_check();
|
||
rkusb_lowformat_check();
|
||
#ifdef CONFIG_ROCKUSB_TIMEOUT_CHECK
|
||
/* if press key enter rockusb, flag = 1 */
|
||
if (rkusb_timeout_check(flag) == 1) {
|
||
/* if timeout, return 1 for enter recovery */
|
||
goto Exit_DoRockusb;
|
||
}
|
||
#endif
|
||
}
|
||
Exit_DoRockusb:
|
||
rk_dwc3_disconnect();
|
||
return 1;
|
||
}
|
||
U_BOOT_CMD(rockusb, CONFIG_SYS_MAXARGS, 1, do_rockusb,
|
||
"Use the UMS [User Mass Storage]",
|
||
"ums <USB_controller> <mmc_dev> e.g. ums 0 0"
|
||
);
|