/* * 2nd - OMAP "second stage" Flash Loader * * Copyright (C) 2008 Guillaume Bougard * Copyright (C) 2005 Luis Recuerda * * 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 "types.h" #include "usb.h" #define USBS_OFFSET 0xfffb4000 #define REG8(addr) (*(volatile u8 *) (addr)) #define REG16(addr) (*(volatile u16 *) (addr)) #define REG32(addr) (*(volatile u32 *) (addr)) #define UREG(addr) REG16 (USBS_OFFSET + (addr)) #define UREG8(addr) REG8 (USBS_OFFSET + (addr)) #define CLOCK_CTRL_REG REG16 (0xfffe0830) #define FUNC_MUX_CTRL_D REG32 (0xfffe1038) #define USBS_REV UREG (0x00) #define USBS_EP_NUM UREG (0x04) #define USBS_DATA UREG (0x08) #define USBS_DATA8 UREG8 (0x08) #define USBS_CTRL UREG (0x0c) #define USBS_STAT_FLG UREG (0x10) #define USBS_RXFSTAT UREG (0x14) #define USBS_SYSCON1 UREG (0x18) #define USBS_SYSCON2 UREG (0x1c) #define USBS_DEVSTAT UREG (0x20) #define USBS_SOF UREG (0x24) #define USBS_IRQ_EN UREG (0x28) #define USBS_DMA_IRQ_EN UREG (0x2c) #define USBS_IRQ_SRC UREG (0x30) #define USBS_EPN_STAT UREG (0x34) #define USBS_DMAN_STAT UREG (0x38) #define USBS_RXDMA_CFG UREG (0x40) #define USBS_TXDMA_CFG UREG (0x44) #define USBS_DATA_DMA UREG (0x48) #define USBS_TXDMA0 UREG (0x50) #define USBS_TXDMA1 UREG (0x54) #define USBS_TXDMA2 UREG (0x58) #define USBS_RXDMA0 UREG (0x60) #define USBS_RXDMA1 UREG (0x64) #define USBS_RXDMA2 UREG (0x68) #define USBS_EP0 UREG (0x80) #define USBS_EP_RX(ep) UREG (0x80+((ep)<<2)) #define USBS_EP_TX(ep) UREG (0xc0+((ep)<<2)) #define _SETUP_SEL 0x40 #define _EP_SEL 0x20 #define _EP_SEL_IN 0x10 #define _EP_SEL_OUT 0x00 static u16 old_sel= 0; static void inline select (u16 sel) { if (old_sel) USBS_EP_NUM= old_sel & ~(_SETUP_SEL | _EP_SEL); USBS_EP_NUM= old_sel= sel; } static void inline unselect (void) { if (old_sel) USBS_EP_NUM= old_sel & ~(_SETUP_SEL | _EP_SEL); old_sel= 0; } #define SELECT(info) select (_EP_SEL | (info)->select) #define SELECT_RX(ep) select (_EP_SEL | _EP_SEL_OUT | (ep)) #define SELECT_TX(ep) select (_EP_SEL | _EP_SEL_IN | (ep)) #define SELECT_SETUP() select (_SETUP_SEL) #define UNSELECT(info) unselect () #define UNSELECT_RX(ep) unselect () #define UNSELECT_TX(ep) unselect () #define UNSELECT_SETUP() unselect () // CTRL: #define _CLR_HALT 0x80 #define _SET_HALT 0x40 #define _SET_FIFO_EN 0x04 #define _CLR_EP 0x02 #define _RESET_EP 0x01 #define STALL_EPn_RX(ep) do { SELECT_RX (ep); USBS_CTRL= _SET_HALT; UNSELECT_RX (ep); } while (0) #define STALL_EPn_TX(ep) do { SELECT_TX (ep); USBS_CTRL= _SET_HALT; UNSELECT_TX (ep); } while (0) // STAT_FLG: #define _STALL 0x20 #define _NAK 0x10 #define _ACK 0x08 #define _FIFO_EN 0x04 #define _NI_FIFO_EMPTY 0x02 #define _NI_FIFO_FULL 0x01 // SYSCON1: #define _CFG_LOCK 0x0100 #define _NAK_EN 0x0010 #define _AUTODEC_DIS 0x0008 #define _SELF_PWR 0x0004 #define _SOFF_DIS 0x0002 #define _PULLUP_EN 0x0001 // SYSCON2: #define _STALL_CMD 0x20 #define _DEV_CFG 0x08 #define _CLR_CFG 0x04 #define STALL_EP0() USBS_SYSCON2= _STALL_CMD // DEVSTAT: #define _DS_USB_Reset 0x20 #define _DS_SUS 0x10 #define _DS_CFG 0x08 #define _DS_ADD 0x04 #define _DS_DEF 0x02 #define _DS_ATT 0x01 // IRQ_EN: #define _SOF_IE 0x80 #define _EPn_RX_IE 0x20 #define _EPn_TX_IE 0x10 #define _DS_CHG_IE 0x08 #define _EP0_IE 0x01 // IRQ_SRC: #define _IRQ_TXn_DONE (1<<10) #define _IRQ_RXn_CNT (1<<9) #define _IRQ_RXn_EOT (1<<8) #define _IRQ_SOF (1<<7) #define _IRQ_EPn_RX (1<<5) #define _IRQ_EPn_TX (1<<4) #define _IRQ_DS_CHG (1<<3) #define _IRQ_SETUP (1<<2) #define _IRQ_EP0_RX (1<<1) #define _IRQ_EP0_TX (1<<0) //////////////////// static const u8 *tx_buffer= 0; static int tx_size= 0; static int tx_complete= 0; static void write_fifo (void) { while (tx_size > 0 && (USBS_STAT_FLG & _NI_FIFO_FULL) == 0) { USBS_DATA8= *tx_buffer++; --tx_size; } tx_complete= tx_size == 0 && (USBS_STAT_FLG & _NI_FIFO_FULL) == 0; USBS_CTRL= _SET_FIFO_EN; } void usb_send (const void *buffer, int size) { tx_buffer= buffer; tx_size= size; tx_complete= 0; SELECT_TX (1); write_fifo (); UNSELECT_TX (1); } int usb_sent (void) { int result= 0; if (USBS_IRQ_SRC & _IRQ_EPn_TX) { int epnum= USBS_EPN_STAT & 0x000f; USBS_IRQ_SRC= _IRQ_EPn_TX; if (epnum == 1) { SELECT_TX (1); if (USBS_STAT_FLG & _ACK) { if (tx_complete) result= 1; else write_fifo (); } UNSELECT_TX (1); } } return result; } //////////////////// static u8 *rx_buffer= NULL; static u8 *rx_buffer0= NULL; static int rx_complete= 0; static int rx_size= 0; static void read_fifo (void) { rx_complete= (USBS_STAT_FLG & _NI_FIFO_FULL) == 0; while ((USBS_STAT_FLG & _NI_FIFO_EMPTY) == 0 && rx_size-- > 0) *rx_buffer++= USBS_DATA8; } void usb_recv (void *buffer, int size) { rx_buffer0= rx_buffer= buffer; rx_size= size; //static int in_rx= 0; //if (!in_rx) { in_rx= 1; SELECT_RX (2); USBS_CTRL= _SET_FIFO_EN; UNSELECT_RX (2); //} } int usb_rcvd (void) { int result= 0; if (USBS_IRQ_SRC & _IRQ_EPn_RX) { int epnum= (USBS_EPN_STAT & 0x0f00) >> 8; USBS_IRQ_SRC= _IRQ_EPn_RX; if (epnum == 2) { SELECT_RX (2); if (USBS_STAT_FLG & _ACK) { read_fifo (); if (rx_complete || rx_size == 0) result= rx_buffer - rx_buffer0; else USBS_CTRL= _SET_FIFO_EN; } UNSELECT_RX (2); } } return result; } void usb_reset() { USBS_SYSCON1 &= ~_PULLUP_EN ; USBS_SYSCON1 |= _PULLUP_EN ; }