blob: ec9d34902eb5029fe3281c20ee7d596248d7ec6b [file] [log] [blame]
/*
* cpu/s5pc1xx/usbd-otg-hs.c
*
* (C) Copyright 2007
* Byungjae Lee, Samsung Erectronics, bjlee@samsung.com.
* - only support for S5PC100
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#if defined(CONFIG_S5PC110) || defined(CONFIG_S5PC210) || defined(CONFIG_S5PC220) || defined(CONFIG_S5P6450) || defined(CONFIG_ARCH_EXYNOS)
#include <command.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include "../../../common/cpu.h"
#include "usbd-otg-hs.h"
#if defined(CONFIG_S5P6450)
DECLARE_GLOBAL_DATA_PTR;
#endif
#undef USB_OTG_DEBUG_SETUP
#ifdef USB_OTG_DEBUG_SETUP
#define DBG_SETUP0(fmt, args...) printf("[%s:%d] " fmt, __FUNCTION__, __LINE__, ##args)
#define DBG_SETUP1(fmt, args...) printf("\t" fmt, ##args)
#define DBG_SETUP2(fmt, args...) printf(fmt, ##args)
#else
#define DBG_SETUP0(fmt, args...) do { } while (0)
#define DBG_SETUP1(fmt, args...) do { } while (0)
#define DBG_SETUP2(fmt, args...) do { } while (0)
#endif
#undef USB_OTG_DEBUG_BULK
#ifdef USB_OTG_DEBUG_BULK
#define DBG_BULK0(fmt, args...) printf("[%s:%d] " fmt, __FUNCTION__, __LINE__, ##args)
#define DBG_BULK1(fmt, args...) printf("\t" fmt, ##args)
#else
#define DBG_BULK0(fmt, args...) do { } while (0)
#define DBG_BULK1(fmt, args...) do { } while (0)
#endif
#define USB_CHECKSUM_EN
#define TRUE 1
#define FALSE 0
#define SUSPEND_RESUME_ON FALSE
u32 s3c_usbd_dn_addr = 0;
u32 s3c_usbd_dn_cnt = 0;
u32 remode_wakeup;
u16 config_value;
int DNW;
int is_fastboot = 0;
int s3c_receive_done = 0;
int s3c_got_header = 0;
USB_OPMODE op_mode = USB_CPU;
USB_SPEED speed = USB_HIGH;
otg_dev_t otg;
get_status_t get_status;
get_intf_t get_intf;
enum EP_INDEX
{
EP0, EP1, EP2, EP3, EP4
};
/*------------------------------------------------*/
/* EP0 state */
enum EP0_STATE
{
EP0_STATE_INIT = 0,
EP0_STATE_GD_DEV_0 = 11,
EP0_STATE_GD_DEV_1 = 12,
EP0_STATE_GD_DEV_2 = 13,
EP0_STATE_GD_CFG_0 = 21,
EP0_STATE_GD_CFG_1 = 22,
EP0_STATE_GD_CFG_2 = 23,
EP0_STATE_GD_CFG_3 = 24,
EP0_STATE_GD_CFG_4 = 25,
EP0_STATE_GD_STR_I0 = 30,
EP0_STATE_GD_STR_I1 = 31,
EP0_STATE_GD_STR_I2 = 32,
EP0_STATE_GD_STR_I3 = 133,
EP0_STATE_GD_DEV_QUALIFIER = 33,
EP0_STATE_INTERFACE_GET = 34,
EP0_STATE_GET_STATUS0 = 35,
EP0_STATE_GET_STATUS1 = 36,
EP0_STATE_GET_STATUS2 = 37,
EP0_STATE_GET_STATUS3 = 38,
EP0_STATE_GET_STATUS4 = 39,
EP0_STATE_GD_OTHER_SPEED = 40,
EP0_STATE_GD_CFG_ONLY_0 = 41,
EP0_STATE_GD_CFG_ONLY_1 = 42,
EP0_STATE_GD_IF_ONLY_0 = 44,
EP0_STATE_GD_IF_ONLY_1 = 45,
EP0_STATE_GD_EP0_ONLY_0 = 46,
EP0_STATE_GD_EP1_ONLY_0 = 47,
EP0_STATE_GD_EP2_ONLY_0 = 48,
EP0_STATE_GD_EP3_ONLY_0 = 49,
EP0_STATE_GD_OTHER_SPEED_HIGH_1 = 51,
EP0_STATE_GD_OTHER_SPEED_HIGH_2 = 52,
EP0_STATE_GD_OTHER_SPEED_HIGH_3 = 53
};
/*definitions related to CSR setting */
/* S5P_OTG_GOTGCTL*/
#define B_SESSION_VALID (0x1<<19)
#define A_SESSION_VALID (0x1<<18)
/* S5P_OTG_GAHBCFG*/
#define PTXFE_HALF (0<<8)
#define PTXFE_ZERO (1<<8)
#define NPTXFE_HALF (0<<7)
#define NPTXFE_ZERO (1<<7)
#define MODE_SLAVE (0<<5)
#define MODE_DMA (1<<5)
#define BURST_SINGLE (0<<1)
#define BURST_INCR (1<<1)
#define BURST_INCR4 (3<<1)
#define BURST_INCR8 (5<<1)
#define BURST_INCR16 (7<<1)
#define GBL_INT_UNMASK (1<<0)
#define GBL_INT_MASK (0<<0)
/* S5P_OTG_GRSTCTL*/
#define AHB_MASTER_IDLE (1u<<31)
#define CORE_SOFT_RESET (0x1<<0)
/* S5P_OTG_GINTSTS/S5P_OTG_GINTMSK core interrupt register */
#define INT_RESUME (1u<<31)
#define INT_DISCONN (0x1<<29)
#define INT_CONN_ID_STS_CNG (0x1<<28)
#define INT_OUT_EP (0x1<<19)
#define INT_IN_EP (0x1<<18)
#define INT_ENUMDONE (0x1<<13)
#define INT_RESET (0x1<<12)
#define INT_SUSPEND (0x1<<11)
#define INT_TX_FIFO_EMPTY (0x1<<5)
#define INT_RX_FIFO_NOT_EMPTY (0x1<<4)
#define INT_SOF (0x1<<3)
#define INT_DEV_MODE (0x0<<0)
#define INT_HOST_MODE (0x1<<1)
/* S5P_OTG_GRXSTSP STATUS*/
#define GLOBAL_OUT_NAK (0x1<<17)
#define OUT_PKT_RECEIVED (0x2<<17)
#define OUT_TRNASFER_COMPLETED (0x3<<17)
#define SETUP_TRANSACTION_COMPLETED (0x4<<17)
#define SETUP_PKT_RECEIVED (0x6<<17)
/* S5P_OTG_DCTL device control register */
#define NORMAL_OPERATION (0x1<<0)
#define SOFT_DISCONNECT (0x1<<1)
#define TEST_J_MODE (TEST_J<<4)
#define TEST_K_MODE (TEST_K<<4)
#define TEST_SE0_NAK_MODE (TEST_SE0_NAK<<4)
#define TEST_PACKET_MODE (TEST_PACKET<<4)
#define TEST_FORCE_ENABLE_MODE (TEST_FORCE_ENABLE<<4)
#define TEST_CONTROL_FIELD (0x7<<4)
/* S5P_OTG_DAINT device all endpoint interrupt register */
#define INT_IN_EP0 (0x1<<0)
#define INT_IN_EP1 (0x1<<1)
#define INT_IN_EP3 (0x1<<3)
#define INT_OUT_EP0 (0x1<<16)
#define INT_OUT_EP2 (0x1<<18)
#define INT_OUT_EP4 (0x1<<20)
/* S5P_OTG_DIEPCTL0/S5P_OTG_DOEPCTL0 */
#define DEPCTL_EPENA (0x1<<31)
#define DEPCTL_EPDIS (0x1<<30)
#define DEPCTL_SNAK (0x1<<27)
#define DEPCTL_CNAK (0x1<<26)
#define DEPCTL_CTRL_TYPE (EP_TYPE_CONTROL<<18)
#define DEPCTL_ISO_TYPE (EP_TYPE_ISOCHRONOUS<<18)
#define DEPCTL_BULK_TYPE (EP_TYPE_BULK<<18)
#define DEPCTL_INTR_TYPE (EP_TYPE_INTERRUPT<<18)
#define DEPCTL_USBACTEP (0x1<<15)
/*ep0 enable, clear nak, next ep0, max 64byte */
#define EPEN_CNAK_EP0_64 (DEPCTL_EPENA|DEPCTL_CNAK|(CONTROL_EP<<11)|(0<<0))
/*ep0 enable, clear nak, next ep0, 8byte */
#define EPEN_CNAK_EP0_8 (DEPCTL_EPENA|DEPCTL_CNAK|(CONTROL_EP<<11)|(3<<0))
/* DIEPCTLn/DOEPCTLn */
#define BACK2BACK_SETUP_RECEIVED (0x1<<6)
#define INTKN_TXFEMP (0x1<<4)
#define NON_ISO_IN_EP_TIMEOUT (0x1<<3)
#define CTRL_OUT_EP_SETUP_PHASE_DONE (0x1<<3)
#define AHB_ERROR (0x1<<2)
#define TRANSFER_DONE (0x1<<0)
/* codes representing languages */
const u8 string_desc0[] =
{
4, STRING_DESCRIPTOR, LANGID_US_L, LANGID_US_H,
};
const u8 dnw_string_desc1[] = /* Manufacturer */
{
(0x14+2), STRING_DESCRIPTOR,
'S', 0x0, 'y', 0x0, 's', 0x0, 't', 0x0, 'e', 0x0,
'm', 0x0, ' ', 0x0, 'M', 0x0, 'C', 0x0, 'U', 0x0,
};
const u8 dnw_string_desc2[] = /* Product */
{
(0x2a+2), STRING_DESCRIPTOR,
'S', 0x0, 'E', 0x0, 'C', 0x0, ' ', 0x0, 'S', 0x0,
'3', 0x0, 'C', 0x0, '6', 0x0, '4', 0x0, '0', 0x0,
'0', 0x0, 'X', 0x0, ' ', 0x0, 'T', 0x0, 'e', 0x0,
's', 0x0, 't', 0x0, ' ', 0x0, 'B', 0x0, '/', 0x0,
'D', 0x0
};
/* setting the device qualifier descriptor and a string descriptor */
const u8 qualifier_desc[] =
{
0x0a, /* 0 desc size */
0x06, /* 1 desc type (DEVICE_QUALIFIER)*/
0x00, /* 2 USB release */
0x02, /* 3 => 2.00*/
0xFF, /* 4 class */
0x00, /* 5 subclass */
0x00, /* 6 protocol */
64, /* 7 max pack size */
0x01, /* 8 number of other-speed configuration */
0x00, /* 9 reserved */
};
const u8 config_full[] =
{
0x09, /* 0 desc size */
0x07, /* 1 desc type (other speed)*/
0x20, /* 2 Total length of data returned */
0x00, /* 3 */
0x01, /* 4 Number of interfaces supported by this speed configuration */
0x01, /* 5 value to use to select configuration */
0x00, /* 6 index of string desc */
/* 7 same as configuration desc */
CONF_ATTR_DEFAULT|CONF_ATTR_SELFPOWERED,
0x19, /* 8 same as configuration desc */
};
const u8 config_full_total[] =
{
0x09, 0x07 ,0x20 ,0x00 ,0x01 ,0x01 ,0x00 ,0xC0 ,0x19,
0x09 ,0x04 ,0x00 ,0x00 ,0x02 ,0xff ,0x00 ,0x00 ,0x00,
0x07 ,0x05 ,0x83 ,0x02 ,0x40 ,0x00 ,0x00,
0x07 ,0x05 ,0x04 ,0x02 ,0x40 ,0x00 ,0x00
};
const u8 config_high[] =
{
0x09, /* 0 desc size */
0x07, /* 1 desc type (other speed)*/
0x20, /* 2 Total length of data returned */
0x00, /* 3 */
0x01, /* 4 Number of interfaces supported by this speed configuration */
0x01, /* 5 value to use to select configuration */
0x00, /* 6 index of string desc */
/* 7 same as configuration desc */
CONF_ATTR_DEFAULT|CONF_ATTR_SELFPOWERED,
0x19, /* 8 same as configuration desc */
};
const u8 config_high_total[] =
{
0x09, 0x07 ,0x20 ,0x00 ,0x01 ,0x01 ,0x00 ,0xC0 ,0x19,
0x09 ,0x04 ,0x00 ,0x00 ,0x02 ,0xff ,0x00 ,0x00 ,0x00,
0x07 ,0x05 ,0x81 ,0x02 ,0x00 ,0x02 ,0x00,
0x07 ,0x05 ,0x02 ,0x02 ,0x00 ,0x02 ,0x00
};
/* Descriptor size */
enum DESCRIPTOR_SIZE
{
DEVICE_DESC_SIZE = sizeof(device_desc_t),
CONFIG_DESC_SIZE = sizeof(config_desc_t),
INTERFACE_DESC_SIZE = sizeof(intf_desc_t),
ENDPOINT_DESC_SIZE = sizeof(ep_desc_t),
DEVICE_QUALIFIER_SIZE = sizeof(qualifier_desc),
OTHER_SPEED_CFG_SIZE = 9
};
/*32 <cfg desc>+<if desc>+<endp0 desc>+<endp1 desc>*/
#define CONFIG_DESC_TOTAL_SIZE \
(CONFIG_DESC_SIZE+INTERFACE_DESC_SIZE+ENDPOINT_DESC_SIZE*2)
#define TEST_PKT_SIZE 53
u8 test_pkt [TEST_PKT_SIZE] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*JKJKJKJK x 9*/
0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, /*JJKKJJKK x 8*/
0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, /*JJJJKKKK x 8*/
0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /*JJJJJJJKKKKKKK x8 - '1'*/
0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, /*'1' + JJJJJJJK x 8*/
0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E /*{JKKKKKKK x 10},JK*/
};
int s3c_usbctl_init(void);
void s3c_usb_set_inep_xfersize(EP_TYPE type, u32 pktcnt, u32 xfersize);
void s3c_usb_write_in_fifo(u8 *buf, int num);
void s3c_usb_read_out_fifo(u8 *buf, int num);
void s3c_usb_init_phy(void)
{
#if defined(CONFIG_ARCH_EXYNOS5)
writel(0x0, USB_CFG_REG);
writel(0x7454, EXYNOS5_OTG_SYS);
udelay(10);
writel(0x0454, EXYNOS5_OTG_SYS);
udelay(10);
#else /* EXYNOS4 or under */
#if defined(CONFIG_S5PC110)
writel(0xa0, S5P_OTG_PHYPWR);
writel(0x3, S5P_OTG_PHYCLK);
#elif defined(CONFIG_S5PC220)
writel(0x0, USB_CFG_REG);
writel(0x7f80, S5P_OTG_PHYPWR);
writel(0x5, S5P_OTG_PHYCLK);
#elif defined(CONFIG_S5PC210)
writel(0x1f80, S5P_OTG_PHYPWR);
writel(0x3, S5P_OTG_PHYCLK);
#elif defined(CONFIG_S5P6450)
writel(0xa0, S5P_OTG_PHYPWR);
writel(0x21, S5P_OTG_PHYCLK);
#endif
writel(0x1, S5P_OTG_RSTCON);
udelay(10);
writel(0x0, S5P_OTG_RSTCON);
udelay(10);
#endif
}
/* OTG PHY Power Off */
void s3c_usb_phy_off(void) {
#if defined(CONFIG_ARCH_EXYNOS5)
writel(0x145F, EXYNOS5_OTG_SYS);
#else
writel(readl(S5P_OTG_PHYPWR)|(0x18), S5P_OTG_PHYPWR);
#endif
#if !defined(CONFIG_S5P6450)
writel(readl(USB_PHY_CONTROL)&~(1<<0), USB_PHY_CONTROL);
#else
writel(readl(OTHERS)|(1<<16), OTHERS);
#endif
}
void s3c_usb_core_soft_reset(void)
{
u32 tmp;
writel(CORE_SOFT_RESET, S5P_OTG_GRSTCTL);
do
{
tmp = readl(S5P_OTG_GRSTCTL);
}while(!(tmp & AHB_MASTER_IDLE));
}
void s3c_usb_wait_cable_insert(void)
{
u32 tmp;
int ucFirst=1;
do {
udelay(50);
tmp = readl(S5P_OTG_GOTGCTL);
if (tmp & (B_SESSION_VALID|A_SESSION_VALID)) {
printf("OTG cable Connected!\n");
break;
} else if(ucFirst == 1) {
printf("Insert a OTG cable into the connector!\n");
ucFirst = 0;
}
} while(1);
}
void s3c_usb_init_core(void)
{
writel(PTXFE_HALF|NPTXFE_HALF|MODE_SLAVE|BURST_SINGLE|GBL_INT_UNMASK,
S5P_OTG_GAHBCFG);
writel( 0<<15 /* PHY Low Power Clock sel */
|1<<14 /* Non-Periodic TxFIFO Rewind Enable */
|0x5<<10 /* Turnaround time */
|0<<9 /* 0:HNP disable, 1:HNP enable */
|0<<8 /* 0:SRP disable, 1:SRP enable */
|0<<7 /* ULPI DDR sel */
|0<<6 /* 0: high speed utmi+, 1: full speed serial */
|0<<4 /* 0: utmi+, 1:ulpi */
|1<<3 /* phy i/f 0:8bit, 1:16bit */
|0x7<<0, /* HS/FS Timeout**/
S5P_OTG_GUSBCFG );
}
void s3c_usb_check_current_mode(u8 *pucMode)
{
u32 tmp;
tmp = readl(S5P_OTG_GINTSTS);
*pucMode = tmp & 0x1;
}
void s3c_usb_set_soft_disconnect(void)
{
u32 tmp;
tmp = readl(S5P_OTG_DCTL);
tmp |= SOFT_DISCONNECT;
writel(tmp, S5P_OTG_DCTL);
}
void s3c_usb_clear_soft_disconnect(void)
{
u32 tmp;
tmp = readl(S5P_OTG_DCTL);
tmp &= ~SOFT_DISCONNECT;
writel(tmp, S5P_OTG_DCTL);
}
void s3c_usb_init_device(void)
{
writel(1<<18|otg.speed<<0, S5P_OTG_DCFG); /* [][1: full speed(30Mhz) 0:high speed]*/
writel(INT_RESUME|INT_OUT_EP|INT_IN_EP|INT_ENUMDONE|
INT_RESET|INT_SUSPEND|INT_RX_FIFO_NOT_EMPTY,
S5P_OTG_GINTMSK); /*gint unmask */
}
int s3c_usbctl_init(void)
{
u8 ucMode;
DBG_SETUP0("USB Control Init\n");
#if defined(CONFIG_S5PC110)||defined(CONFIG_S5PV310) || defined(CONFIG_S5PC210) || defined(CONFIG_S5PC220) || defined(CONFIG_ARCH_EXYNOS)
writel(readl(USB_PHY_CONTROL)|(1<<0), USB_PHY_CONTROL); /*USB PHY0 Enable */ // c110
#elif defined(CONFIG_S5PC100)
writel(readl(OTHERS)|~(1<<16), OTHERS);
#elif defined(CONFIG_S5P6450)
writel(readl(OTHERS)&~(1<<16), OTHERS);
#else
#error "* CFG_ERROR : you have to select proper CPU for Android Fastboot"
#endif
otg.speed = speed;
otg.set_config = 0;
otg.ep0_state = EP0_STATE_INIT;
otg.ep0_substate = 0;
s3c_usb_init_phy();
s3c_usb_core_soft_reset();
s3c_usb_wait_cable_insert();
s3c_usb_init_core();
s3c_usb_check_current_mode(&ucMode);
is_fastboot = 0;
if (ucMode == INT_DEV_MODE) {
s3c_usb_set_soft_disconnect();
udelay(10);
s3c_usb_clear_soft_disconnect();
s3c_usb_init_device();
return 0;
} else {
printf("Error : Current Mode is Host\n");
return 0;
}
}
int s3c_usbc_activate (void)
{
/* dont used in usb high speed, but used in common file cmd_usbd.c */
return 0;
}
int s3c_usb_stop (void)
{
/* dont used in usb high speed, but used in common file cmd_usbd.c */
s3c_usb_core_soft_reset();
s3c_usb_phy_off();
return 0;
}
void s3c_usb_print_pkt(u8 *pt, u8 count)
{
int i;
printf("[s3c_usb_print_pkt:");
for(i=0;i<count;i++)
printf("%x,", pt[i]);
printf("]\n");
}
void s3c_usb_verify_checksum(void)
{
u8 *cs_start, *cs_end;
u16 dnCS;
u16 checkSum;
printf("Checksum is being calculated.");
/* checksum calculation */
cs_start = (u8*)otg.dn_addr;
cs_end = (u8*)(otg.dn_addr+otg.dn_filesize-10);
checkSum = 0;
while(cs_start < cs_end) {
checkSum += *cs_start++;
if(((u32)cs_start&0xfffff)==0) printf(".");
}
#if defined(CONFIG_S5PC110)||defined(CONFIG_S5PV310) || defined(CONFIG_S5PC210) || defined(CONFIG_S5PC220) || defined(CONFIG_ARCH_EXYNOS)
// fixed alignment fault in case when cs_end is odd.
dnCS = (u16)((cs_end[1]<<8) + cs_end[0]);
#elif defined(CONFIG_S5PC100) || defined(CONFIG_S5P6450)
dnCS = *(u16 *)cs_end;
#else
#error "* CFG_ERROR : you have to select proper CPU"
#endif
if (checkSum == dnCS)
{
printf("\nChecksum O.K.\n");
}
else
{
printf("\nChecksum Value => MEM:%x DNW:%x\n",checkSum,dnCS);
printf("Checksum failed.\n\n");
}
}
void s3c_usb_set_inep_xfersize(EP_TYPE type, u32 pktcnt, u32 xfersize)
{
if(type == EP_TYPE_CONTROL)
{
writel((pktcnt<<19)|(xfersize<<0), S5P_OTG_DIEPTSIZ0);
}
else if(type == EP_TYPE_BULK)
{
writel((1<<29)|(pktcnt<<19)|(xfersize<<0), S5P_OTG_DIEPTSIZ_IN);
}
}
void s3c_usb_set_outep_xfersize(EP_TYPE type, u32 pktcnt, u32 xfersize)
{
if(type == EP_TYPE_CONTROL)
{
writel((1<<29)|(pktcnt<<19)|(xfersize<<0), S5P_OTG_DOEPTSIZ0);
}
else if(type == EP_TYPE_BULK)
{
writel((pktcnt<<19)|(xfersize<<0), S5P_OTG_DOEPTSIZ_OUT);
}
}
void s3c_usb_write_ep0_fifo(u8 *buf, int num)
{
int i;
u32 Wr_Data=0;
DBG_SETUP1("[s3c_usb_write_ep0_fifo:");
for(i=0;i<num;i+=4)
{
Wr_Data = ((*(buf+3))<<24)|((*(buf+2))<<16)|((*(buf+1))<<8)|*buf;
DBG_SETUP2(" 0x%08x,", Wr_Data);
writel(Wr_Data, S5P_OTG_EP0_FIFO);
buf += 4;
}
DBG_SETUP2("]\n");
}
void s3c_usb_write_in_fifo(u8 *buf, int num)
{
int i;
u32 data=0;
for(i=0;i<num;i+=4)
{
data=((*(buf+3))<<24)|((*(buf+2))<<16)|((*(buf+1))<<8)|*buf;
writel(data, S5P_OTG_IN_FIFO);
buf += 4;
}
}
void s3c_usb_read_out_fifo(u8 *buf, int num)
{
int i;
u32 data;
for (i=0;i<num;i+=4)
{
data = readl(S5P_OTG_OUT_FIFO);
buf[i] = (u8)data;
buf[i+1] = (u8)(data>>8);
buf[i+2] = (u8)(data>>16);
buf[i+3] = (u8)(data>>24);
}
}
void s3c_usb_get_desc(void)
{
switch (otg.dev_req.wValue_H) {
case DEVICE_DESCRIPTOR:
otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
otg.dev_req.wLength_L);
DBG_SETUP1("DEVICE_DESCRIPTOR = 0x%x \n",otg.req_length);
otg.ep0_state = EP0_STATE_GD_DEV_0;
break;
case CONFIGURATION_DESCRIPTOR:
otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
otg.dev_req.wLength_L);
DBG_SETUP1("CONFIGURATION_DESCRIPTOR = 0x%x \n",otg.req_length);
/* GET_DESCRIPTOR:CONFIGURATION+INTERFACE+ENDPOINT0+ENDPOINT1 */
if (otg.req_length > CONFIG_DESC_SIZE){
otg.ep0_state = EP0_STATE_GD_CFG_0;
} else
otg.ep0_state = EP0_STATE_GD_CFG_ONLY_0;
break;
case STRING_DESCRIPTOR :
DBG_SETUP1("STRING_DESCRIPTOR \n");
switch(otg.dev_req.wValue_L) {
case 0:
otg.ep0_state = EP0_STATE_GD_STR_I0;
break;
case 1:
otg.ep0_state = EP0_STATE_GD_STR_I1;
break;
case 2:
otg.ep0_state = EP0_STATE_GD_STR_I2;
break;
case 3:
otg.ep0_state = EP0_STATE_GD_STR_I3;
break;
default:
break;
}
break;
case ENDPOINT_DESCRIPTOR:
DBG_SETUP1("ENDPOINT_DESCRIPTOR \n");
switch(otg.dev_req.wValue_L&0xf) {
case 0:
otg.ep0_state=EP0_STATE_GD_EP0_ONLY_0;
break;
case 1:
otg.ep0_state=EP0_STATE_GD_EP1_ONLY_0;
break;
default:
break;
}
break;
case DEVICE_QUALIFIER:
otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
otg.dev_req.wLength_L);
DBG_SETUP1("DEVICE_QUALIFIER = 0x%x \n",otg.req_length);
otg.ep0_state = EP0_STATE_GD_DEV_QUALIFIER;
break;
case OTHER_SPEED_CONFIGURATION :
DBG_SETUP1("OTHER_SPEED_CONFIGURATION \n");
otg.req_length = (u32)((otg.dev_req.wLength_H << 8) |
otg.dev_req.wLength_L);
otg.ep0_state = EP0_STATE_GD_OTHER_SPEED;
break;
}
}
void s3c_usb_clear_feature(void)
{
switch (otg.dev_req.bmRequestType) {
case DEVICE_RECIPIENT:
DBG_SETUP1("DEVICE_RECIPIENT \n");
if (otg.dev_req.wValue_L == 1)
remode_wakeup = FALSE;
break;
case ENDPOINT_RECIPIENT:
DBG_SETUP1("ENDPOINT_RECIPIENT \n");
if (otg.dev_req.wValue_L == 0) {
if ((otg.dev_req.wIndex_L & 0x7f) == CONTROL_EP)
get_status.ep_ctrl= 0;
/* IN Endpoint */
if ((otg.dev_req.wIndex_L & 0x7f) == BULK_IN_EP)
get_status.ep_in= 0;
/* OUT Endpoint */
if ((otg.dev_req.wIndex_L & 0x7f) == BULK_OUT_EP)
get_status.ep_out= 0;
}
break;
default:
DBG_SETUP1("\n");
break;
}
otg.ep0_state = EP0_STATE_INIT;
}
void s3c_usb_set_feature(void)
{
u32 tmp;
switch (otg.dev_req.bmRequestType) {
case DEVICE_RECIPIENT:
DBG_SETUP1("DEVICE_RECIPIENT \n");
if (otg.dev_req.wValue_L == 1)
remode_wakeup = TRUE;
break;
case ENDPOINT_RECIPIENT:
DBG_SETUP1("ENDPOINT_RECIPIENT \n");
if (otg.dev_req.wValue_L == 0) {
if ((otg.dev_req.wIndex_L & 0x7f) == CONTROL_EP)
get_status.ep_ctrl= 1;
if ((otg.dev_req.wIndex_L & 0x7f) == BULK_IN_EP)
get_status.ep_in= 1;
if ((otg.dev_req.wIndex_L & 0x7f) == BULK_OUT_EP)
get_status.ep_out= 1;
}
break;
default:
DBG_SETUP1("\n");
break;
}
switch (otg.dev_req.wValue_L) {
case EP_STALL:
/* TBD: additional processing if required */
break;
case TEST_MODE:
if ((0 != otg.dev_req.wIndex_L ) ||(0 != otg.dev_req.bmRequestType))
break;
/* Set TEST MODE*/
tmp = readl(S5P_OTG_DCTL);
tmp = (tmp & ~(TEST_CONTROL_FIELD)) | (TEST_FORCE_ENABLE_MODE);
writel(tmp, S5P_OTG_DCTL);
switch(otg.dev_req.wIndex_H) {
case TEST_J:
/*Set Test J*/
tmp = readl(S5P_OTG_DCTL);
tmp = (tmp & ~(TEST_CONTROL_FIELD)) | (TEST_J_MODE);
writel(tmp, S5P_OTG_DCTL);
break;
case TEST_K:
/*Set Test K*/
tmp = readl(S5P_OTG_DCTL);
tmp = (tmp & ~(TEST_CONTROL_FIELD)) | (TEST_K_MODE);
writel(tmp, S5P_OTG_DCTL);
break;
case TEST_SE0_NAK:
/*Set Test SE0NAK*/
tmp = readl(S5P_OTG_DCTL);
tmp = (tmp & ~(TEST_CONTROL_FIELD)) | (TEST_SE0_NAK_MODE);
writel(tmp, S5P_OTG_DCTL);
break;
case TEST_PACKET:
DBG_SETUP1 ("Test_packet\n");
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, TEST_PKT_SIZE);
s3c_usb_write_ep0_fifo(test_pkt, TEST_PKT_SIZE);
tmp = readl(S5P_OTG_DCTL);
tmp = (tmp & ~(TEST_CONTROL_FIELD)) | (TEST_PACKET_MODE);
writel(tmp, S5P_OTG_DCTL);
DBG_SETUP1 ("S5P_OTG_DCTL=0x%08x\n", tmp);
break;
}
break;
default:
break;
}
otg.ep0_state = EP0_STATE_INIT;
}
void s3c_usb_get_status(void)
{
switch(otg.dev_req.bmRequestType) {
case (0x80): /*device */
DBG_SETUP1("DEVICE\n");
get_status.Device=((u8)remode_wakeup<<1)|0x1; /* SelfPowered */
otg.ep0_state = EP0_STATE_GET_STATUS0;
break;
case (0x81): /*interface */
DBG_SETUP1("INTERFACE\n");
get_status.Interface=0;
otg.ep0_state = EP0_STATE_GET_STATUS1;
break;
case (0x82): /*endpoint */
DBG_SETUP1("ENDPOINT\n");
if ((otg.dev_req.wIndex_L & 0x7f) == CONTROL_EP)
otg.ep0_state = EP0_STATE_GET_STATUS2;
if ((otg.dev_req.wIndex_L & 0x7f) == BULK_IN_EP)
otg.ep0_state = EP0_STATE_GET_STATUS3;
if ((otg.dev_req.wIndex_L & 0x7f) == BULK_OUT_EP)
otg.ep0_state = EP0_STATE_GET_STATUS4;
break;
default:
DBG_SETUP1("\n");
break;
}
}
void s3c_usb_ep0_int_hndlr(void)
{
u16 i;
u32 buf[2]={0x0000, };
u16 addr;
DBG_SETUP0("Event EP0\n");
if (otg.ep0_state == EP0_STATE_INIT) {
for(i=0;i<2;i++)
buf[i] = readl(S5P_OTG_EP0_FIFO);
otg.dev_req.bmRequestType = buf[0];
otg.dev_req.bRequest = buf[0]>>8;
otg.dev_req.wValue_L = buf[0]>>16;
otg.dev_req.wValue_H = buf[0]>>24;
otg.dev_req.wIndex_L = buf[1];
otg.dev_req.wIndex_H = buf[1]>>8;
otg.dev_req.wLength_L = buf[1]>>16;
otg.dev_req.wLength_H = buf[1]>>24;
#ifdef USB_OTG_DEBUG_SETUP
s3c_usb_print_pkt((u8 *)&otg.dev_req, 8);
#endif
switch (otg.dev_req.bRequest) {
case STANDARD_SET_ADDRESS:
/* Set Address Update bit */
addr = (otg.dev_req.wValue_L);
writel(1<<18|addr<<4|otg.speed<<0, S5P_OTG_DCFG);
DBG_SETUP1("S5P_OTG_DCFG : %x, STANDARD_SET_ADDRESS : %d\n",
readl(S5P_OTG_DCFG), addr);
otg.ep0_state = EP0_STATE_INIT;
break;
case STANDARD_SET_DESCRIPTOR:
DBG_SETUP1("STANDARD_SET_DESCRIPTOR \n");
break;
case STANDARD_SET_CONFIGURATION:
DBG_SETUP1("STANDARD_SET_CONFIGURATION \n");
/* Configuration value in configuration descriptor */
config_value = otg.dev_req.wValue_L;
otg.set_config = 1;
otg.ep0_state = EP0_STATE_INIT;
break;
case STANDARD_GET_CONFIGURATION:
DBG_SETUP1("STANDARD_GET_CONFIGURATION \n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
/*ep0 enable, clear nak, next ep0, 8byte */
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
writel(config_value, S5P_OTG_EP0_FIFO);
otg.ep0_state = EP0_STATE_INIT;
break;
case STANDARD_GET_DESCRIPTOR:
DBG_SETUP1("STANDARD_GET_DESCRIPTOR :");
s3c_usb_get_desc();
break;
case STANDARD_CLEAR_FEATURE:
DBG_SETUP1("STANDARD_CLEAR_FEATURE :");
s3c_usb_clear_feature();
break;
case STANDARD_SET_FEATURE:
DBG_SETUP1("STANDARD_SET_FEATURE :");
s3c_usb_set_feature();
break;
case STANDARD_GET_STATUS:
DBG_SETUP1("STANDARD_GET_STATUS :");
s3c_usb_get_status();
break;
case STANDARD_GET_INTERFACE:
DBG_SETUP1("STANDARD_GET_INTERFACE \n");
otg.ep0_state = EP0_STATE_INTERFACE_GET;
break;
case STANDARD_SET_INTERFACE:
DBG_SETUP1("STANDARD_SET_INTERFACE \n");
get_intf.AlternateSetting= otg.dev_req.wValue_L;
otg.ep0_state = EP0_STATE_INIT;
break;
case STANDARD_SYNCH_FRAME:
DBG_SETUP1("STANDARD_SYNCH_FRAME \n");
otg.ep0_state = EP0_STATE_INIT;
break;
default:
break;
}
}
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, otg.ctrl_max_pktsize);
/*clear nak, next ep0, 64byte */
writel(((1<<26)|(CONTROL_EP<<11)|(0<<0)), S5P_OTG_DIEPCTL0);
}
void s3c_usb_set_otherspeed_conf_desc(u32 length)
{
/* Standard device descriptor */
if (length ==9)
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 9);
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo(((u8 *)&config_full)+0, 9);
}
else if(length ==32)
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 32);
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo(((u8 *)&config_full_total)+0, 32);
}
otg.ep0_state = EP0_STATE_INIT;
}
void s3c_usb_transfer_ep0(void)
{
const u8 *string_desc1, *string_desc2, *string_desc3;
u32 string_desc1_size, string_desc2_size, string_desc3_size;
if (is_fastboot) {
/* string_desc1 = fboot_string_desc1;
string_desc2 = fboot_string_desc2;
string_desc3 = fboot_string_desc3;
string_desc1_size = sizeof(fboot_string_desc1);
string_desc2_size = sizeof(fboot_string_desc2);
string_desc3_size = sizeof(fboot_string_desc3);
*/ } else {
string_desc1 = dnw_string_desc1;
string_desc2 = dnw_string_desc2;
string_desc3 = dnw_string_desc2;
string_desc1_size = sizeof(dnw_string_desc1);
string_desc2_size = sizeof(dnw_string_desc2);
string_desc3_size = sizeof(dnw_string_desc2);
}
DBG_SETUP0("otg.ep0_state = %d\n", otg.ep0_state);
switch (otg.ep0_state) {
case EP0_STATE_INIT:
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 0);
/*ep0 enable, clear nak, next ep0, 8byte */
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
DBG_SETUP1("EP0_STATE_INIT\n");
break;
/* GET_DESCRIPTOR:DEVICE */
case EP0_STATE_GD_DEV_0:
DBG_SETUP1("EP0_STATE_GD_DEV_0 :");
/*ep0 enable, clear nak, next ep0, max 64byte */
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
if (otg.req_length < DEVICE_DESC_SIZE) {
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, otg.req_length);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.dev))+0, otg.req_length);
} else {
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, DEVICE_DESC_SIZE);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.dev))+0, DEVICE_DESC_SIZE);
}
otg.ep0_state = EP0_STATE_INIT;
break;
/* GET_DESCRIPTOR:CONFIGURATION+INTERFACE+ENDPOINT0+ENDPOINT1 */
case EP0_STATE_GD_CFG_0:
DBG_SETUP1("EP0_STATE_GD_CFG_0 :");
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
if(otg.req_length<CONFIG_DESC_TOTAL_SIZE)
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, otg.req_length);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.config))+0, otg.req_length);
}
else
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, CONFIG_DESC_TOTAL_SIZE);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.config))+0, CONFIG_DESC_TOTAL_SIZE);
}
otg.ep0_state = EP0_STATE_INIT;
break;
case EP0_STATE_GD_OTHER_SPEED:
DBG_SETUP1("EP0_STATE_GD_OTHER_SPEED\n");
s3c_usb_set_otherspeed_conf_desc(otg.req_length);
break;
/* GET_DESCRIPTOR:CONFIGURATION ONLY*/
case EP0_STATE_GD_CFG_ONLY_0:
DBG_SETUP1("EP0_STATE_GD_CFG_ONLY_0:");
if(otg.req_length<CONFIG_DESC_SIZE)
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, otg.req_length);
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.config))+0, otg.req_length);
}
else
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, CONFIG_DESC_SIZE);
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.config))+0,
CONFIG_DESC_SIZE);
}
otg.ep0_state = EP0_STATE_INIT;
break;
/* GET_DESCRIPTOR:INTERFACE ONLY */
case EP0_STATE_GD_IF_ONLY_0:
DBG_SETUP1("EP0_STATE_GD_IF_ONLY_0 :");
if(otg.req_length<INTERFACE_DESC_SIZE)
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, otg.req_length);
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.intf))+0, otg.req_length);
}
else
{
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, INTERFACE_DESC_SIZE);
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.intf))+0, INTERFACE_DESC_SIZE);
}
otg.ep0_state = EP0_STATE_INIT;
break;
/* GET_DESCRIPTOR:ENDPOINT 1 ONLY */
case EP0_STATE_GD_EP0_ONLY_0:
DBG_SETUP1("EP0_STATE_GD_EP0_ONLY_0\n");
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, ENDPOINT_DESC_SIZE);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.ep1))+0, ENDPOINT_DESC_SIZE);
otg.ep0_state = EP0_STATE_INIT;
break;
/* GET_DESCRIPTOR:ENDPOINT 2 ONLY */
case EP0_STATE_GD_EP1_ONLY_0:
DBG_SETUP1("EP0_STATE_GD_EP1_ONLY_0\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, ENDPOINT_DESC_SIZE);
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo(((u8 *)&(otg.desc.ep2))+0, ENDPOINT_DESC_SIZE);
otg.ep0_state = EP0_STATE_INIT;
break;
/* GET_DESCRIPTOR:STRING */
case EP0_STATE_GD_STR_I0:
DBG_SETUP1("EP0_STATE_GD_STR_I0\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, sizeof(string_desc0));
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)string_desc0, sizeof(string_desc0));
otg.ep0_state = EP0_STATE_INIT;
break;
case EP0_STATE_GD_STR_I1:
DBG_SETUP1("EP0_STATE_GD_STR_I1 %d\n", otg.ep0_substate);
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, string_desc1_size);
if ((otg.ep0_substate*otg.ctrl_max_pktsize+otg.ctrl_max_pktsize)
< string_desc1_size) {
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)string_desc1+(otg.ep0_substate*otg.ctrl_max_pktsize),
otg.ctrl_max_pktsize);
otg.ep0_state = EP0_STATE_GD_STR_I1;
otg.ep0_substate++;
} else {
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)string_desc1+(otg.ep0_substate*otg.ctrl_max_pktsize),
string_desc1_size-(otg.ep0_substate*otg.ctrl_max_pktsize));
otg.ep0_state = EP0_STATE_INIT;
otg.ep0_substate = 0;
}
break;
case EP0_STATE_GD_STR_I2:
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, string_desc2_size);
if ((otg.ep0_substate*otg.ctrl_max_pktsize+otg.ctrl_max_pktsize)
< string_desc2_size) {
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)string_desc2+(otg.ep0_substate*otg.ctrl_max_pktsize),
otg.ctrl_max_pktsize);
otg.ep0_state = EP0_STATE_GD_STR_I2;
otg.ep0_substate++;
} else {
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)string_desc2+(otg.ep0_substate*otg.ctrl_max_pktsize),
string_desc2_size-(otg.ep0_substate*otg.ctrl_max_pktsize));
otg.ep0_state = EP0_STATE_INIT;
otg.ep0_substate = 0;
}
DBG_SETUP1("EP0_STATE_GD_STR_I2 %d", otg.ep0_substate);
break;
case EP0_STATE_GD_STR_I3:
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, string_desc3_size);
if ((otg.ep0_substate*otg.ctrl_max_pktsize+otg.ctrl_max_pktsize)
< string_desc3_size) {
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)string_desc3+(otg.ep0_substate*otg.ctrl_max_pktsize),
otg.ctrl_max_pktsize);
otg.ep0_state = EP0_STATE_GD_STR_I3;
otg.ep0_substate++;
} else {
writel(EPEN_CNAK_EP0_64, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)string_desc3+(otg.ep0_substate*otg.ctrl_max_pktsize),
string_desc3_size-(otg.ep0_substate*otg.ctrl_max_pktsize));
otg.ep0_state = EP0_STATE_INIT;
otg.ep0_substate = 0;
}
DBG_SETUP1("EP0_STATE_GD_STR_I3 %d", otg.ep0_substate);
break;
case EP0_STATE_INTERFACE_GET:
DBG_SETUP1("EP0_STATE_INTERFACE_GET\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)&get_intf+0, 1);
otg.ep0_state = EP0_STATE_INIT;
break;
case EP0_STATE_GET_STATUS0:
DBG_SETUP1("EP0_STATE_GET_STATUS0\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)&get_status+0, 1);
otg.ep0_state = EP0_STATE_INIT;
break;
case EP0_STATE_GET_STATUS1:
DBG_SETUP1("EP0_STATE_GET_STATUS1\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)&get_status+1, 1);
otg.ep0_state = EP0_STATE_INIT;
break;
case EP0_STATE_GET_STATUS2:
DBG_SETUP1("EP0_STATE_GET_STATUS2\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)&get_status+2, 1);
otg.ep0_state = EP0_STATE_INIT;
break;
case EP0_STATE_GET_STATUS3:
DBG_SETUP1("EP0_STATE_GET_STATUS3\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)&get_status+3, 1);
otg.ep0_state = EP0_STATE_INIT;
break;
case EP0_STATE_GET_STATUS4:
DBG_SETUP1("EP0_STATE_GET_STATUS4\n");
s3c_usb_set_inep_xfersize(EP_TYPE_CONTROL, 1, 1);
writel(EPEN_CNAK_EP0_8, S5P_OTG_DIEPCTL0);
s3c_usb_write_ep0_fifo((u8 *)&get_status+4, 1);
otg.ep0_state = EP0_STATE_INIT;
break;
default:
break;
}
}
void s3c_usb_int_bulkin(void)
{
u8* bulkin_buf;
u32 remain_cnt;
DBG_BULK0("Bulk In Function\n");
bulkin_buf = (u8*)otg.up_ptr;
remain_cnt = otg.up_size- ((u32)otg.up_ptr - otg.up_addr);
DBG_BULK1("bulkin_buf = 0x%x,remain_cnt = 0x%x \n", bulkin_buf, remain_cnt);
if (remain_cnt > otg.bulkin_max_pktsize) {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, 1, otg.bulkin_max_pktsize);
/*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt 64*/
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkin_max_pktsize<<0,
S5P_OTG_DIEPCTL_IN);
s3c_usb_write_in_fifo(bulkin_buf, otg.bulkin_max_pktsize);
otg.up_ptr += otg.bulkin_max_pktsize;
while(readl(S5P_OTG_DIEPCTL_IN) & (1<<31));
} else if(remain_cnt > 0) {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, 1, remain_cnt);
/*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt 64*/
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkin_max_pktsize<<0,
S5P_OTG_DIEPCTL_IN);
s3c_usb_write_in_fifo(bulkin_buf, remain_cnt);
otg.up_ptr += remain_cnt;
while(readl(S5P_OTG_DIEPCTL_IN) & (1<<31));
} else { /*remain_cnt = 0*/
writel((DEPCTL_SNAK|DEPCTL_BULK_TYPE), S5P_OTG_DIEPCTL_IN);
}
}
void s3c_usb_upload_start(void)
{
u8 tmp_buf[12];
u32 check;
s3c_usb_read_out_fifo((u8 *)tmp_buf, 10);
check = *((u8 *)(tmp_buf+8)) + (*((u8 *)(tmp_buf+9))<<8);
if (check==0x1) {
otg.up_addr =
*((u8 *)(tmp_buf+0))+
(*((u8 *)(tmp_buf+1))<<8)+
(*((u8 *)(tmp_buf+2))<<16)+
(*((u8 *)(tmp_buf+3))<<24);
otg.up_size =
*((u8 *)(tmp_buf+4))+
(*((u8 *)(tmp_buf+5))<<8)+
(*((u8 *)(tmp_buf+6))<<16)+
(*((u8 *)(tmp_buf+7))<<24);
otg.up_ptr=(u8 *)otg.up_addr;
DBG_BULK1("UploadAddress : 0x%x, UploadSize: %d\n",
otg.up_addr, otg.up_size);
if (otg.op_mode == USB_CPU) {
if (otg.up_size > otg.bulkin_max_pktsize) {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, 1,
otg.bulkin_max_pktsize);
} else {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, 1,
otg.up_size);
}
/*ep1 enable, clear nak, bulk, usb active, max pkt 64*/
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkin_max_pktsize<<0,
S5P_OTG_DIEPCTL_IN);
} else if ((otg.op_mode == USB_DMA) && (otg.up_size > 0)) {
u32 pktcnt, remainder;
DBG_BULK1("Dma Start for IN PKT \n");
writel(MODE_DMA|BURST_INCR4|GBL_INT_UNMASK,
S5P_OTG_GAHBCFG);
writel(INT_RESUME|INT_OUT_EP|INT_IN_EP| INT_ENUMDONE|
INT_RESET|INT_SUSPEND, S5P_OTG_GINTMSK);
writel((u32)otg.up_ptr, S5P_OTG_DIEPDMA_IN);
pktcnt = (u32)(otg.up_size/otg.bulkin_max_pktsize);
remainder = (u32)(otg.up_size%otg.bulkin_max_pktsize);
if(remainder != 0) {
pktcnt += 1;
}
if (pktcnt > 1023) {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, 1023,
(otg.bulkin_max_pktsize*1023));
} else {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, pktcnt,
otg.up_size);
}
/*ep1 enable, clear nak, bulk, usb active, next ep1, max pkt */
writel(1u<<31|1<<26|2<<18|1<<15|BULK_IN_EP<<11|
otg.bulkin_max_pktsize<<0,
S5P_OTG_DIEPCTL_IN);
}
}
otg.dn_filesize=0;
}
void s3c_usb_download_start(u32 fifo_cnt_byte)
{
u8 tmp_buf[8];
s3c_usb_read_out_fifo((u8 *)tmp_buf, 8);
DBG_BULK1("downloadFileSize==0, 1'st BYTE_READ_CNT_REG : %x\n",
fifo_cnt_byte);
otg.dn_addr=s3c_usbd_dn_addr;
otg.dn_filesize=
*((u8 *)(tmp_buf+4))+
(*((u8 *)(tmp_buf+5))<<8)+
(*((u8 *)(tmp_buf+6))<<16)+
(*((u8 *)(tmp_buf+7))<<24);
otg.dn_ptr=(u8 *)otg.dn_addr;
DBG_BULK1("downloadAddress : 0x%x, downloadFileSize: %x\n",
otg.dn_addr, otg.dn_filesize);
/* The first 8-bytes are deleted.*/
s3c_usb_read_out_fifo((u8 *)otg.dn_ptr, fifo_cnt_byte-8);
otg.dn_ptr += fifo_cnt_byte-8;
if (otg.op_mode == USB_CPU) {
s3c_usb_set_outep_xfersize(EP_TYPE_BULK, 1,
otg.bulkout_max_pktsize);
/*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt 64*/
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkout_max_pktsize<<0,
S5P_OTG_DOEPCTL_OUT);
} else if (otg.dn_filesize>otg.bulkout_max_pktsize) {
u32 pkt_cnt, remain_cnt;
DBG_BULK1("downloadFileSize!=0, Dma Start for 2nd OUT PKT \n");
writel(INT_RESUME|INT_OUT_EP|INT_IN_EP|INT_ENUMDONE|
INT_RESET|INT_SUSPEND, S5P_OTG_GINTMSK); /*gint unmask */
writel(MODE_DMA|BURST_INCR4|GBL_INT_UNMASK,
S5P_OTG_GAHBCFG);
writel((u32)otg.dn_ptr, S5P_OTG_DOEPDMA_OUT);
pkt_cnt = (u32)(otg.dn_filesize-otg.bulkout_max_pktsize)/otg.bulkout_max_pktsize;
remain_cnt = (u32)((otg.dn_filesize-otg.bulkout_max_pktsize)%otg.bulkout_max_pktsize);
if(remain_cnt != 0) {
pkt_cnt += 1;
}
if (pkt_cnt > 1023) {
s3c_usb_set_outep_xfersize(EP_TYPE_BULK, 1023,
(otg.bulkout_max_pktsize*1023));
} else {
s3c_usb_set_outep_xfersize(EP_TYPE_BULK, pkt_cnt,
(otg.dn_filesize-otg.bulkout_max_pktsize));
}
/*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt 64*/
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkout_max_pktsize<<0,
S5P_OTG_DOEPCTL_OUT);
}
}
void s3c_usb_download_continue(u32 fifo_cnt_byte)
{
if (otg.op_mode == USB_CPU) {
s3c_usb_read_out_fifo((u8 *)otg.dn_ptr, fifo_cnt_byte);
otg.dn_ptr += fifo_cnt_byte;
DBG_BULK1("downloadFileSize!=0, 2nd BYTE_READ_CNT_REG = 0x%x, m_pDownPt = 0x%x\n",
fifo_cnt_byte, otg.dn_ptr);
s3c_usb_set_outep_xfersize(EP_TYPE_BULK, 1, otg.bulkout_max_pktsize);
/*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt 64*/
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkout_max_pktsize<<0,
S5P_OTG_DOEPCTL_OUT);
/* USB format : addr(4)+size(4)+data(n)+cs(2) */
if (((u32)otg.dn_ptr - otg.dn_addr) >= (otg.dn_filesize - 8)) {
printf("Download Done!! Download Address: 0x%x, Download Filesize:0x%x\n",
otg.dn_addr, (otg.dn_filesize-10));
s3c_usbd_dn_cnt = otg.dn_filesize-10;
s3c_usbd_dn_addr = otg.dn_addr;
#ifdef USB_CHECKSUM_EN
s3c_usb_verify_checksum();
#endif
s3c_receive_done = 1;
}
}\
}
void s3c_usb_int_bulkout(u32 fifo_cnt_byte)
{
DBG_BULK0("Bulk Out Function : otg.dn_filesize=0x%x\n", otg.dn_filesize);
if (otg.dn_filesize==0) {
if (fifo_cnt_byte == 10) {
s3c_usb_upload_start();
} else {
s3c_usb_download_start(fifo_cnt_byte);
}
} else {
s3c_usb_download_continue(fifo_cnt_byte);
}
}
void s3c_usb_dma_in_done(void)
{
s32 remain_cnt;
DBG_BULK0("DMA IN : Transfer Done\n");
otg.up_ptr = (u8 *)readl(S5P_OTG_DIEPDMA_IN);
remain_cnt = otg.up_size- ((u32)otg.up_ptr - otg.up_addr);
if (remain_cnt>0) {
u32 pktcnt, remainder;
pktcnt = (u32)(remain_cnt/otg.bulkin_max_pktsize);
remainder = (u32)(remain_cnt%otg.bulkin_max_pktsize);
if(remainder != 0) {
pktcnt += 1;
}
DBG_SETUP1("remain_cnt : %d \n", remain_cnt);
if (pktcnt> 1023) {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, 1023,
(otg.bulkin_max_pktsize*1023));
} else {
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, pktcnt,
remain_cnt);
}
/*ep1 enable, clear nak, bulk, usb active, next ep1, max pkt */
writel(1u<<31|1<<26|2<<18|1<<15|BULK_IN_EP<<11|otg.bulkin_max_pktsize<<0,
S5P_OTG_DIEPCTL_IN);
} else
DBG_SETUP1("DMA IN : Transfer Complete\n");
}
void s3c_usb_dma_out_done(void)
{
s32 remain_cnt;
DBG_BULK1("DMA OUT : Transfer Done\n");
otg.dn_ptr = (u8 *)readl(S5P_OTG_DOEPDMA_OUT);
remain_cnt = otg.dn_filesize - ((u32)otg.dn_ptr - otg.dn_addr + 8);
if (remain_cnt>0) {
u32 pktcnt, remainder;
pktcnt = (u32)(remain_cnt/otg.bulkout_max_pktsize);
remainder = (u32)(remain_cnt%otg.bulkout_max_pktsize);
if(remainder != 0) {
pktcnt += 1;
}
DBG_BULK1("remain_cnt : %d \n", remain_cnt);
if (pktcnt> 1023) {
s3c_usb_set_outep_xfersize(EP_TYPE_BULK, 1023,
(otg.bulkout_max_pktsize*1023));
} else {
s3c_usb_set_outep_xfersize(EP_TYPE_BULK, pktcnt,
remain_cnt);
}
/*ep3 enable, clear nak, bulk, usb active, next ep3, max pkt 64*/
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkout_max_pktsize<<0,
S5P_OTG_DOEPCTL_OUT);
} else {
DBG_BULK1("DMA OUT : Transfer Complete\n");
udelay(500); /*for FPGA ???*/
}
}
void s3c_usb_set_all_outep_nak(void)
{
u8 i;
u32 tmp;
for(i=0;i<16;i++)
{
tmp = readl(S5P_OTG_DOEPCTL0+0x20*i);
tmp |= DEPCTL_SNAK;
writel(tmp, S5P_OTG_DOEPCTL0+0x20*i);
}
}
void s3c_usb_clear_all_outep_nak(void)
{
u8 i;
u32 tmp;
for(i=0;i<16;i++)
{
tmp = readl(S5P_OTG_DOEPCTL0+0x20*i);
tmp |= (DEPCTL_EPENA|DEPCTL_CNAK);
writel(tmp, S5P_OTG_DOEPCTL0+0x20*i);
}
}
void s3c_usb_set_max_pktsize(USB_SPEED speed)
{
if (speed == USB_HIGH)
{
otg.speed = USB_HIGH;
otg.ctrl_max_pktsize = HS_CTRL_PKT_SIZE;
otg.bulkin_max_pktsize = HS_BULK_PKT_SIZE;
otg.bulkout_max_pktsize = HS_BULK_PKT_SIZE;
}
else
{
otg.speed = USB_FULL;
otg.ctrl_max_pktsize = FS_CTRL_PKT_SIZE;
otg.bulkin_max_pktsize = FS_BULK_PKT_SIZE;
otg.bulkout_max_pktsize = FS_BULK_PKT_SIZE;
}
}
void s3c_usb_set_endpoint(void)
{
/* Unmask S5P_OTG_DAINT source */
writel(0xff, S5P_OTG_DIEPINT0);
writel(0xff, S5P_OTG_DOEPINT0);
writel(0xff, S5P_OTG_DIEPINT_IN);
writel(0xff, S5P_OTG_DOEPINT_OUT);
/* Init For Ep0*/
/*MPS:64bytes */
writel(((1<<26)|(CONTROL_EP<<11)|(0<<0)), S5P_OTG_DIEPCTL0);
/*ep0 enable, clear nak */
writel((1u<<31)|(1<<26)|(0<<0), S5P_OTG_DOEPCTL0);
}
void s3c_usb_set_descriptors(void)
{
/* Standard device descriptor */
otg.desc.dev.bLength=DEVICE_DESC_SIZE; /*0x12*/
otg.desc.dev.bDescriptorType=DEVICE_DESCRIPTOR;
otg.desc.dev.bDeviceClass=0xFF; /* 0x0*/
otg.desc.dev.bDeviceSubClass=0x0;
otg.desc.dev.bDeviceProtocol=0x0;
otg.desc.dev.bMaxPacketSize0=otg.ctrl_max_pktsize;
otg.desc.dev.idVendorL=0xE8; /*0x45;*/
otg.desc.dev.idVendorH=0x04; /*0x53;*/
otg.desc.dev.idProductL=0x34; /*0x00*/
otg.desc.dev.idProductH=0x12; /*0x64*/
otg.desc.dev.bcdDeviceL=0x00;
otg.desc.dev.bcdDeviceH=0x01;
otg.desc.dev.iManufacturer=0x1; /* index of string descriptor */
otg.desc.dev.iProduct=0x2; /* index of string descriptor */
otg.desc.dev.iSerialNumber=0x0;
otg.desc.dev.bNumConfigurations=0x1;
if (otg.speed == USB_FULL) {
otg.desc.dev.bcdUSBL=0x10;
otg.desc.dev.bcdUSBH=0x01; /* Ver 1.10*/
}
else {
otg.desc.dev.bcdUSBL=0x00;
otg.desc.dev.bcdUSBH=0x02; /* Ver 2.0*/
}
/* Standard configuration descriptor */
otg.desc.config.bLength=CONFIG_DESC_SIZE; /* 0x9 bytes */
otg.desc.config.bDescriptorType=CONFIGURATION_DESCRIPTOR;
otg.desc.config.wTotalLengthL=CONFIG_DESC_TOTAL_SIZE;
otg.desc.config.wTotalLengthH=0;
otg.desc.config.bNumInterfaces=1;
/* dbg descConf.bConfigurationValue=2; // why 2? There's no reason.*/
otg.desc.config.bConfigurationValue=1;
otg.desc.config.iConfiguration=0;
otg.desc.config.bmAttributes=CONF_ATTR_DEFAULT|CONF_ATTR_SELFPOWERED; /* bus powered only.*/
otg.desc.config.maxPower=25; /* draws 50mA current from the USB bus.*/
/* Standard interface descriptor */
otg.desc.intf.bLength=INTERFACE_DESC_SIZE; /* 9*/
otg.desc.intf.bDescriptorType=INTERFACE_DESCRIPTOR;
otg.desc.intf.bInterfaceNumber=0x0;
otg.desc.intf.bAlternateSetting=0x0; /* ?*/
otg.desc.intf.bNumEndpoints = 2; /* # of endpoints except EP0*/
otg.desc.intf.bInterfaceClass=0xff; /* 0x0 ?*/
otg.desc.intf.bInterfaceSubClass=0x0;
otg.desc.intf.bInterfaceProtocol=0x0;
otg.desc.intf.iInterface=0x0;
/* Standard endpoint0 descriptor */
otg.desc.ep1.bLength=ENDPOINT_DESC_SIZE;
otg.desc.ep1.bDescriptorType=ENDPOINT_DESCRIPTOR;
otg.desc.ep1.bEndpointAddress=BULK_IN_EP|EP_ADDR_IN;
otg.desc.ep1.bmAttributes=EP_ATTR_BULK;
otg.desc.ep1.wMaxPacketSizeL=(u8)otg.bulkin_max_pktsize; /* 64*/
otg.desc.ep1.wMaxPacketSizeH=(u8)(otg.bulkin_max_pktsize>>8);
otg.desc.ep1.bInterval=0x0; /* not used */
/* Standard endpoint1 descriptor */
otg.desc.ep2.bLength=ENDPOINT_DESC_SIZE;
otg.desc.ep2.bDescriptorType=ENDPOINT_DESCRIPTOR;
otg.desc.ep2.bEndpointAddress=BULK_OUT_EP|EP_ADDR_OUT;
otg.desc.ep2.bmAttributes=EP_ATTR_BULK;
otg.desc.ep2.wMaxPacketSizeL=(u8)otg.bulkout_max_pktsize; /* 64*/
otg.desc.ep2.wMaxPacketSizeH=(u8)(otg.bulkout_max_pktsize>>8);
otg.desc.ep2.bInterval=0x0; /* not used */
}
void s3c_usb_check_speed(USB_SPEED *speed)
{
u32 status;
status = readl(S5P_OTG_DSTS); /* System status read */
*speed = (USB_SPEED)((status&0x6) >>1);
}
void s3c_usb_clear_dnfile_info(void)
{
otg.dn_addr = 0;
otg.dn_filesize = 0;
otg.dn_ptr = 0;
}
void s3c_usb_clear_upfile_info(void)
{
otg.up_addr= 0;
otg.up_size= 0;
otg.up_ptr = 0;
}
int s3c_usb_check_setconf(void)
{
if (otg.set_config == 0)
return FALSE;
else
return TRUE;
}
void s3c_usb_set_opmode(USB_OPMODE mode)
{
otg.op_mode = mode;
writel(INT_RESUME|INT_OUT_EP|INT_IN_EP|INT_ENUMDONE|
INT_RESET|INT_SUSPEND|INT_RX_FIFO_NOT_EMPTY,
S5P_OTG_GINTMSK); /*gint unmask */
writel(MODE_SLAVE|BURST_SINGLE|GBL_INT_UNMASK, S5P_OTG_GAHBCFG);
s3c_usb_set_outep_xfersize(EP_TYPE_BULK, 1, otg.bulkout_max_pktsize);
s3c_usb_set_inep_xfersize(EP_TYPE_BULK, 1, 0);
/*bulk out ep enable, clear nak, bulk, usb active, next ep3, max pkt */
writel(1u<<31|1<<26|2<<18|1<<15|otg.bulkout_max_pktsize<<0,
S5P_OTG_DOEPCTL_OUT);
/*bulk in ep enable, clear nak, bulk, usb active, next ep1, max pkt */
writel(0u<<31|1<<26|2<<18|1<<15|otg.bulkin_max_pktsize<<0,
S5P_OTG_DIEPCTL_IN);
}
void s3c_usb_reset(void)
{
s3c_usb_set_all_outep_nak();
otg.ep0_state = EP0_STATE_INIT;
writel(((1<<BULK_OUT_EP)|(1<<CONTROL_EP))<<16|((1<<BULK_IN_EP)|(1<<CONTROL_EP)),
S5P_OTG_DAINTMSK);
writel(CTRL_OUT_EP_SETUP_PHASE_DONE|AHB_ERROR|TRANSFER_DONE,
S5P_OTG_DOEPMSK);
writel(INTKN_TXFEMP|NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE,
S5P_OTG_DIEPMSK);
/* Rx FIFO Size */
writel(RX_FIFO_SIZE, S5P_OTG_GRXFSIZ);
/* Non Periodic Tx FIFO Size */
writel(NPTX_FIFO_SIZE<<16| NPTX_FIFO_START_ADDR<<0, S5P_OTG_GNPTXFSIZ);
s3c_usb_clear_all_outep_nak();
/*clear device address */
writel(readl(S5P_OTG_DCFG)&~(0x7f<<4), S5P_OTG_DCFG);
if(SUSPEND_RESUME_ON) {
writel(readl(S5P_OTG_PCGCCTL)&~(1<<0), S5P_OTG_PCGCCTL);
}
}
int s3c_usb_set_init(void)
{
u32 status;
status = readl(S5P_OTG_DSTS); /* System status read */
/* Set if Device is High speed or Full speed */
if (((status&0x6) >>1) == USB_HIGH) {
DBG_SETUP1("High Speed Detection\n");
s3c_usb_set_max_pktsize(USB_HIGH);
}
else if(((status&0x6) >>1) == USB_FULL) {
DBG_SETUP1("Full Speed Detec tion\n");
s3c_usb_set_max_pktsize(USB_FULL);
}
else {
printf("**** Error:Neither High_Speed nor Full_Speed\n");
return FALSE;
}
s3c_usb_set_endpoint();
/* if (is_fastboot)
fboot_usb_set_descriptors();
else
*/ s3c_usb_set_descriptors();
s3c_usb_clear_dnfile_info();
s3c_usb_set_opmode(op_mode);
return TRUE;
}
void s3c_usb_pkt_receive(void)
{
u32 rx_status;
u32 fifo_cnt_byte;
rx_status = readl(S5P_OTG_GRXSTSP);
DBG_SETUP0("S5P_OTG_GRXSTSP = 0x%x\n", rx_status);
if ((rx_status & (0xf<<17)) == SETUP_PKT_RECEIVED) {
DBG_SETUP1("SETUP_PKT_RECEIVED\n");
s3c_usb_ep0_int_hndlr();
} else if ((rx_status & (0xf<<17)) == OUT_PKT_RECEIVED) {
fifo_cnt_byte = (rx_status & 0x7ff0)>>4;
DBG_SETUP1("OUT_PKT_RECEIVED\n");
if((rx_status & BULK_OUT_EP)&&(fifo_cnt_byte)) {
/* if (is_fastboot)
fboot_usb_int_bulkout(fifo_cnt_byte);
else
*/ s3c_usb_int_bulkout(fifo_cnt_byte);
if( otg.op_mode == USB_CPU )
writel(INT_RESUME|INT_OUT_EP|INT_IN_EP|
INT_ENUMDONE|INT_RESET|INT_SUSPEND|
INT_RX_FIFO_NOT_EMPTY,
S5P_OTG_GINTMSK);
return;
}
} else if ((rx_status & (0xf<<17)) == GLOBAL_OUT_NAK) {
DBG_SETUP1("GLOBAL_OUT_NAK\n");
} else if ((rx_status & (0xf<<17)) == OUT_TRNASFER_COMPLETED) {
DBG_SETUP1("OUT_TRNASFER_COMPLETED\n");
} else if ((rx_status & (0xf<<17)) == SETUP_TRANSACTION_COMPLETED) {
DBG_SETUP1("SETUP_TRANSACTION_COMPLETED\n");
} else {
DBG_SETUP1("Reserved\n");
}
}
void s3c_usb_transfer(void)
{
u32 ep_int;
u32 check_dma;
u32 ep_int_status;
ep_int = readl(S5P_OTG_DAINT);
DBG_SETUP0("S5P_OTG_DAINT = 0x%x", ep_int);
if (ep_int & (1<<CONTROL_EP)) {
ep_int_status = readl(S5P_OTG_DIEPINT0);
DBG_SETUP1("S5P_OTG_DIEPINT0 : %x \n", ep_int_status);
if (ep_int_status & INTKN_TXFEMP) {
u32 uNTxFifoSpace;
do {
uNTxFifoSpace=readl(S5P_OTG_GNPTXSTS)&0xffff;
}while(uNTxFifoSpace<otg.ctrl_max_pktsize);
s3c_usb_transfer_ep0();
}
writel(ep_int_status, S5P_OTG_DIEPINT0); /* Interrupt Clear */
} else if (ep_int & ((1<<CONTROL_EP)<<16)) {
ep_int_status = readl(S5P_OTG_DOEPINT0);
DBG_SETUP1("S5P_OTG_DOEPINT0 : %x \n", ep_int_status);
s3c_usb_set_outep_xfersize(EP_TYPE_CONTROL, 1, 8);
writel(1u<<31|1<<26, S5P_OTG_DOEPCTL0); /*ep0 enable, clear nak */
writel(ep_int_status, S5P_OTG_DOEPINT0); /* Interrupt Clear */
} else if(ep_int & (1<<BULK_IN_EP)) {
ep_int_status = readl(S5P_OTG_DIEPINT_IN);
DBG_BULK1("S5P_OTG_DIEPINT_IN : %x \n", ep_int_status);
writel(ep_int_status, S5P_OTG_DIEPINT_IN); /* Interrupt Clear */
if ( (ep_int_status&INTKN_TXFEMP) && otg.op_mode == USB_CPU) {
/* if (is_fastboot)
fboot_usb_int_bulkin();
else
*/ s3c_usb_int_bulkin();
}
check_dma = readl(S5P_OTG_GAHBCFG);
if ((check_dma&MODE_DMA)&&(ep_int_status&TRANSFER_DONE))
s3c_usb_dma_in_done();
} else if (ep_int & ((1<<BULK_OUT_EP)<<16)) {
ep_int_status = readl(S5P_OTG_DOEPINT_OUT);
DBG_BULK1("S5P_OTG_DOEPINT_OUT : 0x%x\n", ep_int_status);
writel(ep_int_status, S5P_OTG_DOEPINT_OUT); /* Interrupt Clear */
check_dma = readl(S5P_OTG_GAHBCFG);
if ((check_dma&MODE_DMA)&&(ep_int_status&TRANSFER_DONE)) {
s3c_usb_dma_out_done();
}
}
}
#define ERROR -1
#define OK 0
int s3c_udc_int_hndlr(void)
{
u32 int_status;
int tmp;
int ret = ERROR;
int_status = readl(S5P_OTG_GINTSTS); /* Core Interrupt Register */
writel(int_status, S5P_OTG_GINTSTS); /* Interrupt Clear */
DBG_SETUP0("*** USB OTG Interrupt(S5P_OTG_GINTSTS: 0x%08x) ****\n",
int_status);
if (int_status & INT_RESET) {
DBG_SETUP1("INT_RESET\n");
writel(INT_RESET, S5P_OTG_GINTSTS); /* Interrupt Clear */
s3c_usb_reset();
ret = OK;
}
if (int_status & INT_ENUMDONE) {
DBG_SETUP1("INT_ENUMDONE :");
writel(INT_ENUMDONE, S5P_OTG_GINTSTS); /* Interrupt Clear */
tmp = s3c_usb_set_init();
ret = OK;
if (tmp == FALSE)
return ret;
}
if (int_status & INT_RESUME) {
DBG_SETUP1("INT_RESUME\n");
writel(INT_RESUME, S5P_OTG_GINTSTS); /* Interrupt Clear */
if(SUSPEND_RESUME_ON) {
writel(readl(S5P_OTG_PCGCCTL)&~(1<<0), S5P_OTG_PCGCCTL);
DBG_SETUP1("INT_RESUME\n");
}
ret = OK;
}
if (int_status & INT_SUSPEND) {
DBG_SETUP1("INT_SUSPEND\n");
writel(INT_SUSPEND, S5P_OTG_GINTSTS); /* Interrupt Clear */
if(SUSPEND_RESUME_ON) {
writel(readl(S5P_OTG_PCGCCTL)|(1<<0), S5P_OTG_PCGCCTL);
}
ret = OK;
}
if(int_status & INT_RX_FIFO_NOT_EMPTY) {
DBG_SETUP1("INT_RX_FIFO_NOT_EMPTY\n");
/* Read only register field */
writel(INT_RESUME|INT_OUT_EP|INT_IN_EP|
INT_ENUMDONE|INT_RESET|INT_SUSPEND,
S5P_OTG_GINTMSK);
s3c_usb_pkt_receive();
writel(INT_RESUME|INT_OUT_EP|INT_IN_EP|INT_ENUMDONE|
INT_RESET |INT_SUSPEND|INT_RX_FIFO_NOT_EMPTY,
S5P_OTG_GINTMSK); /*gint unmask */
ret = OK;
}
if ((int_status & INT_IN_EP) || (int_status & INT_OUT_EP)) {
DBG_SETUP1("INT_IN or OUT_EP\n");
/* Read only register field */
s3c_usb_transfer();
ret = OK;
}
return ret;
}
#endif