aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/usbd-otg-hs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/usbd-otg-hs.c')
-rw-r--r--drivers/usb/gadget/usbd-otg-hs.c1936
1 files changed, 1936 insertions, 0 deletions
diff --git a/drivers/usb/gadget/usbd-otg-hs.c b/drivers/usb/gadget/usbd-otg-hs.c
new file mode 100644
index 000000000..ec9d34902
--- /dev/null
+++ b/drivers/usb/gadget/usbd-otg-hs.c
@@ -0,0 +1,1936 @@
+/*
+ * 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