forked from len0rd/rockbox
M:Robe 500: Mostly complete USB driver, supports BULK mode currently and gets about 2 MB/s writes vs 1.1 MB/s on the OF. Mostly tested against Linux, preliminary testing in Windows appears to work. There is currently a bug in the attach process where it only works once per boot that needs to be fixed. There are a few other minor M:Robe 500 changes as well.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21208 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
f8a8619615
commit
4a483bb1bf
12 changed files with 1048 additions and 56 deletions
|
@ -271,7 +271,9 @@ usbstack/usb_charging_only.c
|
||||||
#ifdef USB_ENABLE_HID
|
#ifdef USB_ENABLE_HID
|
||||||
usbstack/usb_hid.c
|
usbstack/usb_hid.c
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_USBOTG == USBOTG_ARC
|
#if CONFIG_USBOTG == USBOTG_M66591
|
||||||
|
drivers/m66591.c
|
||||||
|
#elif CONFIG_USBOTG == USBOTG_ARC
|
||||||
target/arm/usb-drv-arc.c
|
target/arm/usb-drv-arc.c
|
||||||
#elif CONFIG_USBOTG == USBOTG_ISP1583
|
#elif CONFIG_USBOTG == USBOTG_ISP1583
|
||||||
drivers/isp1583.c
|
drivers/isp1583.c
|
||||||
|
|
847
firmware/drivers/m66591.c
Normal file
847
firmware/drivers/m66591.c
Normal file
|
@ -0,0 +1,847 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id: usb-mr500.c 18487 2008-09-10 20:14:22Z bertrik $
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 by Karl Kurbjun
|
||||||
|
* Portions Copyright (C) 2007 by Catalin Patulea
|
||||||
|
*
|
||||||
|
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#define LOGF_ENABLE
|
||||||
|
|
||||||
|
#include "system.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "usb_ch9.h"
|
||||||
|
#include "usb_core.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "usb_drv.h"
|
||||||
|
#include "logf.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "ata.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "usb-target.h"
|
||||||
|
#include "m66591.h"
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* These are the driver specific defines.
|
||||||
|
******************************************************************************/
|
||||||
|
#define HISPEED
|
||||||
|
|
||||||
|
/* Right now sending blocks till the full transfer has completed, this needs to
|
||||||
|
* be fixed so that it does not require a block. (USB_TRAN_LOCK ideally would
|
||||||
|
* not be set).
|
||||||
|
*/
|
||||||
|
#define USB_TRAN_BLOCK
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* The following functions are all helpers which should not be called directly
|
||||||
|
* from the USB stack. They should only be called by eachother, or the USB
|
||||||
|
* stack visible functions.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
static volatile unsigned short * pipe_ctrl_addr(int pipe);
|
||||||
|
static void pipe_handshake(int pipe, int handshake);
|
||||||
|
static void pipe_c_select (int pipe, bool dir);
|
||||||
|
#if !defined(USB_TRAN_BLOCK)
|
||||||
|
static int pipe_buffer_size (int pipe);
|
||||||
|
#endif
|
||||||
|
static int pipe_maxpack_size (int pipe);
|
||||||
|
static void control_received(void);
|
||||||
|
static void transfer_complete(int endpoint);
|
||||||
|
static int mxx_transmit_receive(int endpoint);
|
||||||
|
static int mxx_queue(int endpoint, void * ptr, int length, bool send);
|
||||||
|
|
||||||
|
struct M66591_epstat {
|
||||||
|
unsigned char dir; /* endpoint direction */
|
||||||
|
char *buf; /* user buffer to store data */
|
||||||
|
int length; /* how match data will fit */
|
||||||
|
volatile int count; /* actual data count */
|
||||||
|
bool waiting; /* is there data to transfer? */
|
||||||
|
bool busy; /* has the pipe been requested for use? */
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static struct M66591_epstat M66591_eps[USB_NUM_ENDPOINTS];
|
||||||
|
|
||||||
|
/* This function is used to return the control address for each pipe */
|
||||||
|
static volatile unsigned short * pipe_ctrl_addr(int pipe) {
|
||||||
|
if(pipe==0) {
|
||||||
|
return &M66591_DCPCTRL;
|
||||||
|
} else {
|
||||||
|
return &M66591_PIPECTRL1 + (pipe-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function sets the pipe/endpoint handshake */
|
||||||
|
static void pipe_handshake(int pipe, int handshake) {
|
||||||
|
handshake&=0x03;
|
||||||
|
|
||||||
|
if(handshake == PIPE_SHAKE_STALL) {
|
||||||
|
if( *(pipe_ctrl_addr(pipe)) & 0x03 ) {
|
||||||
|
*(pipe_ctrl_addr(pipe)) = 0x03;
|
||||||
|
} else {
|
||||||
|
*(pipe_ctrl_addr(pipe)) = 0x02;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*(pipe_ctrl_addr(pipe)) = handshake;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function chooses the pipe desired and waits the required time before
|
||||||
|
* warites/reads are valid */
|
||||||
|
static void pipe_c_select (int pipe, bool dir) {
|
||||||
|
M66591_CPORT_CTRL0 = pipe | (1<<10) | (dir<<5);
|
||||||
|
|
||||||
|
// Wait for the Pipe to be valid;
|
||||||
|
udelay(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(USB_TRAN_BLOCK)
|
||||||
|
/* This returns the maximum buffer size of each pipe. On this device the size
|
||||||
|
* is fixed.
|
||||||
|
*/
|
||||||
|
static int pipe_buffer_size (int pipe) {
|
||||||
|
switch(pipe) {
|
||||||
|
case 0:
|
||||||
|
return 256;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return 1024;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
return 512;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
return 64;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This function returns the maximum packet size for each endpoint/pipe. It is
|
||||||
|
* Currently only setup to support Highspeed mode.
|
||||||
|
*/
|
||||||
|
static int pipe_maxpack_size (int pipe) {
|
||||||
|
switch(pipe) {
|
||||||
|
case 0:
|
||||||
|
/* DCP max packet size is configurable */
|
||||||
|
return M66591_DCP_MXPKSZ;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
return 512;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
return 64;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a helper function that is only called from the interupt handler. It
|
||||||
|
* copies the control packet information from the PHY and notifies the stack.
|
||||||
|
*/
|
||||||
|
static void control_received(void) {
|
||||||
|
/* copy setup data from packet */
|
||||||
|
static struct usb_ctrlrequest temp;
|
||||||
|
|
||||||
|
memcpy(&temp, (unsigned char*)&M66591_USB_REQ0, 8);
|
||||||
|
|
||||||
|
logf("mxx: bReqType=0x%02x bReq=0x%02x wVal=0x%04x"
|
||||||
|
" wIdx=0x%04x wLen=0x%04x",
|
||||||
|
temp.bRequestType, temp.bRequest, temp.wValue,
|
||||||
|
temp.wIndex, temp.wLength);
|
||||||
|
|
||||||
|
/* acknowledge packet recieved (clear valid) */
|
||||||
|
M66591_INTSTAT_MAIN &= ~(1<<3);
|
||||||
|
|
||||||
|
usb_core_control_request(&temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a helper function, it is used to notife the stack that a transfer is
|
||||||
|
* done.
|
||||||
|
*/
|
||||||
|
static void transfer_complete(int endpoint) {
|
||||||
|
M66591_INTCFG_EMP &= ~(1 << endpoint);
|
||||||
|
logf("mxx: ep %d transfer complete", endpoint);
|
||||||
|
int temp=M66591_eps[endpoint].dir ? USB_DIR_IN : USB_DIR_OUT;
|
||||||
|
usb_core_transfer_complete(endpoint, temp, 0,
|
||||||
|
M66591_eps[endpoint].length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the main transmit routine that is typically called from the interrupt
|
||||||
|
* handler (the queue function calls it in some situations)
|
||||||
|
*/
|
||||||
|
static int mxx_transmit_receive(int endpoint) {
|
||||||
|
logf("mxx: do start");
|
||||||
|
|
||||||
|
/* Only the lower 15 bits of the endpoint correlate to the pipe number.
|
||||||
|
* For example pipe 2 will corelate to endpoint 0x82, so the upper bits
|
||||||
|
* need to be masked out.
|
||||||
|
*/
|
||||||
|
endpoint &= 0x7F;
|
||||||
|
|
||||||
|
int i; /* Used as a loop counter */
|
||||||
|
int length; /* Used in transfers to determine the amount to send/receive */
|
||||||
|
|
||||||
|
bool send=M66591_eps[endpoint].dir;
|
||||||
|
|
||||||
|
/* This is used as the internal buffer pointer */
|
||||||
|
unsigned short *ptrs;
|
||||||
|
|
||||||
|
/* Choose the pipe that data is being transfered on */
|
||||||
|
pipe_c_select(endpoint, send);
|
||||||
|
|
||||||
|
/* Check to see if the endpoint is ready and give it some time to become
|
||||||
|
* ready. If it runs out of time exit out as an error.
|
||||||
|
*/
|
||||||
|
i = 0;
|
||||||
|
while (!(M66591_CPORT_CTRL1&(1<<13))) {
|
||||||
|
if (i++ > 100000) {
|
||||||
|
logf("mxx: FIFO %d not ready", endpoint);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write to FIFO */
|
||||||
|
if(send) {
|
||||||
|
int maxpack=pipe_maxpack_size(endpoint);
|
||||||
|
#if defined(USB_TRAN_BLOCK)
|
||||||
|
length = M66591_eps[endpoint].length;
|
||||||
|
#else
|
||||||
|
int bufsize=pipe_buffer_size(endpoint);
|
||||||
|
length=MIN(M66591_eps[endpoint].length, bufsize);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Calculate the position in the buffer, all transfers should be 2-byte
|
||||||
|
* aligned till the last packet or short packet.
|
||||||
|
*/
|
||||||
|
ptrs = (unsigned short *)(M66591_eps[endpoint].buf
|
||||||
|
+ M66591_eps[endpoint].count);
|
||||||
|
|
||||||
|
/* Start sending data in 16-bit words */
|
||||||
|
for (i = 0; i < (length>>1); i++) {
|
||||||
|
/* This wait is dangerous in the event htat something happens to
|
||||||
|
* the PHY pipe where it never becomes ready again, should probably
|
||||||
|
* add a timeout, and ideally completely remove.
|
||||||
|
*/
|
||||||
|
while(!(M66591_CPORT_CTRL1&(1<<13))){};
|
||||||
|
|
||||||
|
M66591_CPORT = *ptrs++;
|
||||||
|
M66591_eps[endpoint].count+=2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the length is odd, send the last byte after setting the byte width
|
||||||
|
* of the FIFO.
|
||||||
|
*/
|
||||||
|
if(length & 0x01) {
|
||||||
|
/* Unset MBW (8-bit transfer) */
|
||||||
|
M66591_CPORT_CTRL0 &= ~(1<<10);
|
||||||
|
M66591_CPORT = *((unsigned char *)ptrs - 1);
|
||||||
|
M66591_eps[endpoint].count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set BVAL if length is not a multiple of the maximum packet size */
|
||||||
|
if( (length == 0) || (length % maxpack != 0) ) {
|
||||||
|
logf("mxx: do set BVAL");
|
||||||
|
M66591_CPORT_CTRL1 |= (1<<15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the transfer is complete set up interrupts to notify when FIFO is
|
||||||
|
* EMPTY, disable READY and let the handler know that there is nothing
|
||||||
|
* left to transfer on this pipe.
|
||||||
|
*/
|
||||||
|
if(M66591_eps[endpoint].count == M66591_eps[endpoint].length) {
|
||||||
|
/* Enable Empty flag */
|
||||||
|
M66591_INTCFG_EMP |= 1 << endpoint;
|
||||||
|
/* Disable ready flag */
|
||||||
|
M66591_INTCFG_RDY &= ~(1 << endpoint);
|
||||||
|
/* Nothing left to transfer */
|
||||||
|
M66591_eps[endpoint].waiting=false;
|
||||||
|
} else {
|
||||||
|
/* There is still data to transfer, make sure READY is enabled */
|
||||||
|
M66591_INTCFG_RDY |= 1 << endpoint;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Read data from FIFO */
|
||||||
|
|
||||||
|
/* Read the number of bytes that the PHY received */
|
||||||
|
int receive_length=M66591_CPORT_CTRL1 & 0x03FF;
|
||||||
|
|
||||||
|
/* The number of bytes to actually read is either what's left of the
|
||||||
|
* amount requested, or the amount that the PHY received. Choose the
|
||||||
|
* smaller of the two.
|
||||||
|
*/
|
||||||
|
length = MIN(M66591_eps[endpoint].length - M66591_eps[endpoint].count,
|
||||||
|
receive_length);
|
||||||
|
|
||||||
|
/* If the length is zero, just clear the buffer as specified in the
|
||||||
|
* datasheet. Otherwise read in the data (in 16-bit pieces */
|
||||||
|
if(length==0) {
|
||||||
|
/* Set the BCLR bit */
|
||||||
|
M66591_CPORT_CTRL1 |= 1<<14;
|
||||||
|
} else {
|
||||||
|
/* Set the position in the buffer */
|
||||||
|
ptrs = (unsigned short *)(M66591_eps[endpoint].buf
|
||||||
|
+ M66591_eps[endpoint].count);
|
||||||
|
|
||||||
|
/* Read in the data (buffer size should be even). The PHY cannot
|
||||||
|
* switch from 16-bit mode to 8-bit mode on an OUT buffer.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ((length+1)>>1); i++) {
|
||||||
|
*ptrs++ = M66591_CPORT;
|
||||||
|
M66591_eps[endpoint].count+=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the length was odd subtract 1 from the count */
|
||||||
|
M66591_eps[endpoint].count -= (length&0x01);
|
||||||
|
|
||||||
|
/* If the requested size of data was received, or the data received was
|
||||||
|
* less than the maximum packet size end the transfer.
|
||||||
|
*/
|
||||||
|
if( (M66591_eps[endpoint].count == M66591_eps[endpoint].length)
|
||||||
|
|| (length % pipe_maxpack_size(endpoint)) ) {
|
||||||
|
|
||||||
|
/* If the host tries to send anything else the FIFO is not ready/
|
||||||
|
* enabled yet (NAK).
|
||||||
|
*/
|
||||||
|
pipe_handshake(endpoint, PIPE_SHAKE_NAK);
|
||||||
|
/* Tell the interrupt handler that transfer is complete. */
|
||||||
|
M66591_eps[endpoint].waiting=false;
|
||||||
|
/* Disable ready */
|
||||||
|
M66591_INTCFG_RDY &= ~(1 << endpoint);
|
||||||
|
|
||||||
|
/* Let the stack know that the transfer is complete */
|
||||||
|
if(endpoint!=0)
|
||||||
|
transfer_complete(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logf("mxx: do done ep %d %s len: %d cnt: %d", endpoint,
|
||||||
|
send ? "out" : "in", length, M66591_eps[endpoint].count);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is used to start transfers. It is a helper function for the
|
||||||
|
* usb_drv_send_nonblocking, usb_drv_send, and usb_drv_receive functions.
|
||||||
|
*/
|
||||||
|
static int mxx_queue(int endpoint, void * ptr, int length, bool send) {
|
||||||
|
/* Disable IRQs */
|
||||||
|
int flags = disable_irq_save();
|
||||||
|
|
||||||
|
/* Only the lower 15 bits of the endpoint correlate to the pipe number.
|
||||||
|
* For example pipe 2 will corelate to endpoint 0x82, so the upper bits
|
||||||
|
* need to be masked out.
|
||||||
|
*/
|
||||||
|
endpoint &= 0x7F;
|
||||||
|
|
||||||
|
/* Initialize the enpoint status registers used for the transfer */
|
||||||
|
M66591_eps[endpoint].buf=ptr;
|
||||||
|
M66591_eps[endpoint].length=length;
|
||||||
|
M66591_eps[endpoint].count=0;
|
||||||
|
M66591_eps[endpoint].dir=send;
|
||||||
|
M66591_eps[endpoint].waiting=true;
|
||||||
|
|
||||||
|
logf("mxx: queue ep %d %s, len: %d", endpoint, send ? "out" : "in", length);
|
||||||
|
|
||||||
|
/* Pick the pipe that communications are happening on */
|
||||||
|
pipe_c_select(endpoint, send);
|
||||||
|
|
||||||
|
/* All transfers start with a BUF handshake */
|
||||||
|
pipe_handshake(endpoint, PIPE_SHAKE_BUF);
|
||||||
|
|
||||||
|
/* This USB PHY takes care of control completion packets by setting the
|
||||||
|
* CCPL bit in EP0 (endpoint 0, or DCP). If the control state is "write no
|
||||||
|
* data tranfer" then we just need to set the CCPL bit (hopefully)
|
||||||
|
* regardless of what the stack said to send.
|
||||||
|
*/
|
||||||
|
int control_state = (M66591_INTSTAT_MAIN & 0x07);
|
||||||
|
if(endpoint==0 && control_state==CTRL_WTND) {
|
||||||
|
logf("mxx: queue ep 0 ctls: 5, set ccpl");
|
||||||
|
|
||||||
|
/* Set CCPL */
|
||||||
|
M66591_DCPCTRL |= 1<<2;
|
||||||
|
} else {
|
||||||
|
/* This is the standard case for transmitting data */
|
||||||
|
if(send) {
|
||||||
|
/* If the pipe is not ready don't try and send right away; instead
|
||||||
|
* just set the READY interrupt so that the handler can initiate
|
||||||
|
* the transfer.
|
||||||
|
*/
|
||||||
|
if((M66591_CPORT_CTRL1&(1<<13))) {
|
||||||
|
mxx_transmit_receive(endpoint);
|
||||||
|
} else {
|
||||||
|
M66591_INTCFG_RDY |= 1 << endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(length==0) {
|
||||||
|
transfer_complete(endpoint);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* When receiving data, just enable the ready interrupt, the PHY
|
||||||
|
* will trigger it and then the reads can start.
|
||||||
|
*/
|
||||||
|
M66591_INTCFG_RDY |= 1 << endpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-enable IRQs */
|
||||||
|
restore_irq(flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* This is the interrupt handler for this driver. It should be called from the
|
||||||
|
* target interrupt handler routine (eg. GPIO3 on M:Robe 500).
|
||||||
|
******************************************************************************/
|
||||||
|
void USB_DEVICE(void) {
|
||||||
|
int pipe_restore=M66591_CPORT_CTRL0;
|
||||||
|
logf("mxx: INT BEGIN tick: %d\n", (int) current_tick);
|
||||||
|
|
||||||
|
logf("mxx: sMAIN0: 0x%04x, sRDY: 0x%04x",
|
||||||
|
M66591_INTSTAT_MAIN, M66591_INTSTAT_RDY);
|
||||||
|
logf("mxx: sNRDY: 0x%04x, sEMP: 0x%04x",
|
||||||
|
M66591_INTSTAT_NRDY, M66591_INTSTAT_EMP);
|
||||||
|
|
||||||
|
/* VBUS (connected) interrupt */
|
||||||
|
while ( M66591_INTSTAT_MAIN & (1<<15) ) {
|
||||||
|
M66591_INTSTAT_MAIN &= ~(1<<15);
|
||||||
|
|
||||||
|
/* If device is not clocked, interrupt flag must be set manually */
|
||||||
|
if ( !(M66591_TRN_CTRL & (1<<10)) ) {
|
||||||
|
M66591_INTSTAT_MAIN |= (1<<15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resume interrupt: This is not used. Extra logic needs to be added similar
|
||||||
|
* to the VBUS interrupt incase the PHY clock is not running.
|
||||||
|
*/
|
||||||
|
if(M66591_INTSTAT_MAIN & (1<<14)) {
|
||||||
|
M66591_INTSTAT_MAIN &= ~(1<<14);
|
||||||
|
logf("mxx: RESUME");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device state transition interrupt: Not used, but useful for debugging */
|
||||||
|
if(M66591_INTSTAT_MAIN & (1<<12)) {
|
||||||
|
M66591_INTSTAT_MAIN &= ~(1<<12);
|
||||||
|
logf("mxx: DEV state CHANGE=%d",
|
||||||
|
((M66591_INTSTAT_MAIN & (0x07<<4)) >> 4) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Control transfer stage interrupt */
|
||||||
|
if(M66591_INTSTAT_MAIN & (1<<11)) {
|
||||||
|
M66591_INTSTAT_MAIN &= ~(1<<11);
|
||||||
|
int control_state = (M66591_INTSTAT_MAIN & 0x07);
|
||||||
|
|
||||||
|
logf("mxx: CTRT with CTSQ=%d", control_state);
|
||||||
|
|
||||||
|
switch ( control_state ) {
|
||||||
|
case CTRL_IDLE:
|
||||||
|
transfer_complete(0);
|
||||||
|
break;
|
||||||
|
case CTRL_RTDS:
|
||||||
|
case CTRL_WTDS:
|
||||||
|
case CTRL_WTND:
|
||||||
|
// If data is not valid stop
|
||||||
|
if(!(M66591_INTSTAT_MAIN & (1<<3)) ) {
|
||||||
|
logf("mxx: CTRT interrupt but VALID is false");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
control_received();
|
||||||
|
break;
|
||||||
|
case CTRL_RTSS:
|
||||||
|
case CTRL_WTSS:
|
||||||
|
pipe_handshake(0, PIPE_SHAKE_BUF);
|
||||||
|
M66591_DCPCTRL |= 1<<2; // Set CCPL
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logf("mxx: CTRT with unknown CTSQ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIFO EMPTY interrupt: when this happens the transfer should be complete.
|
||||||
|
* When the interrupt occurs notify the stack.
|
||||||
|
*/
|
||||||
|
if(M66591_INTSTAT_MAIN & (1<<10)) {
|
||||||
|
int i;
|
||||||
|
logf("mxx: INT EMPTY: 0x%04x", M66591_INTSTAT_EMP);
|
||||||
|
|
||||||
|
for(i=0; i<USB_NUM_ENDPOINTS; i++) {
|
||||||
|
if(M66591_INTSTAT_EMP&(1<<i)) {
|
||||||
|
/* Clear the empty flag */
|
||||||
|
M66591_INTSTAT_EMP=~(1<<i);
|
||||||
|
/* Notify the stack */
|
||||||
|
transfer_complete(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIFO NOT READY interrupt: This is not used, but included incase the
|
||||||
|
* interrupt is endabled.
|
||||||
|
*/
|
||||||
|
if(M66591_INTSTAT_MAIN & (1<<9)) {
|
||||||
|
logf("mxx: INT NOT READY: 0x%04x", M66591_INTSTAT_NRDY);
|
||||||
|
M66591_INTSTAT_NRDY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIFO READY interrupt: This just initiates transfers if they are needed */
|
||||||
|
if(M66591_INTSTAT_MAIN & (1<<8)) {
|
||||||
|
int i;
|
||||||
|
logf("mxx: INT READY: 0x%04x", M66591_INTSTAT_RDY);
|
||||||
|
|
||||||
|
for(i=0; i<USB_NUM_ENDPOINTS; i++) {
|
||||||
|
/* Was this endpoint ready and waiting */
|
||||||
|
if(M66591_INTSTAT_RDY&(1<<i) && M66591_eps[i].waiting) {
|
||||||
|
/* Clear the ready flag */
|
||||||
|
M66591_INTSTAT_RDY=~(1<<i);
|
||||||
|
/* It was ready and waiting so start a transfer */
|
||||||
|
mxx_transmit_receive(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that the INTStatus register is completely cleared. */
|
||||||
|
M66591_INTSTAT_MAIN = 0;
|
||||||
|
|
||||||
|
/* Restore the pipe state before the interrupt occured */
|
||||||
|
M66591_CPORT_CTRL0=pipe_restore;
|
||||||
|
logf("\nmxx: INT END");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* The following functions are all called by and visible to the USB stack.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/* The M55691 handles this automatically, nothing to do */
|
||||||
|
void usb_drv_set_address(int address) {
|
||||||
|
(void) address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function sets the standard test modes, it is not required, but might as
|
||||||
|
* well implement it since the hardware supports it
|
||||||
|
*/
|
||||||
|
void usb_drv_set_test_mode(int mode) {
|
||||||
|
/* This sets the test bits and assumes that mode is from 0 to 0x04 */
|
||||||
|
M66591_TESTMODE &= 0x0007;
|
||||||
|
M66591_TESTMODE |= mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request an unused endpoint, support for interrupt endpoints needs addition */
|
||||||
|
int usb_drv_request_endpoint(int type, int dir) {
|
||||||
|
int ep;
|
||||||
|
int pipecfg = 0;
|
||||||
|
|
||||||
|
if (type != USB_ENDPOINT_XFER_BULK)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* The endpoint/pipes are hard coded: This could be more flexible */
|
||||||
|
if (dir == USB_DIR_IN) {
|
||||||
|
pipecfg |= (1<<4);
|
||||||
|
ep = 2;
|
||||||
|
} else {
|
||||||
|
ep = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!M66591_eps[ep].busy) {
|
||||||
|
M66591_eps[ep].busy = true;
|
||||||
|
M66591_eps[ep].dir = dir;
|
||||||
|
} else {
|
||||||
|
logf("mxx: ep %d busy", ep);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
M66591_PIPE_CFGSEL=ep;
|
||||||
|
|
||||||
|
pipecfg |= 1<<15 | 1<<9 | 1<<8;
|
||||||
|
|
||||||
|
pipe_handshake(ep, PIPE_SHAKE_NAK);
|
||||||
|
|
||||||
|
// Setup the flags
|
||||||
|
M66591_PIPE_CFGWND=pipecfg;
|
||||||
|
|
||||||
|
logf("mxx: ep req ep#: %d config: 0x%04x", ep, M66591_PIPE_CFGWND);
|
||||||
|
|
||||||
|
return ep | dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used by stack to tell the helper functions that the pipe is not in use */
|
||||||
|
void usb_drv_release_endpoint(int ep) {
|
||||||
|
int flags;
|
||||||
|
ep &= 0x7f;
|
||||||
|
|
||||||
|
if (ep < 1 || ep > USB_NUM_ENDPOINTS || M66591_eps[ep].busy == false)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
flags = disable_irq_save();
|
||||||
|
|
||||||
|
logf("mxx: ep %d release", ep);
|
||||||
|
|
||||||
|
M66591_eps[ep].busy = false;
|
||||||
|
M66591_eps[ep].dir = -1;
|
||||||
|
|
||||||
|
restore_irq(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Periodically called to check if a cable was plugged into the device */
|
||||||
|
inline int usb_detect(void)
|
||||||
|
{
|
||||||
|
if(M66591_INTSTAT_MAIN&(1<<7))
|
||||||
|
return USB_INSERTED;
|
||||||
|
else
|
||||||
|
return USB_EXTRACTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_enable(bool on) {
|
||||||
|
logf("mxx: %s: %s", __FUNCTION__, on ? "true" : "false");
|
||||||
|
if (on)
|
||||||
|
usb_core_init();
|
||||||
|
else
|
||||||
|
usb_core_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is where the driver stuff starts */
|
||||||
|
void usb_drv_init(void) {
|
||||||
|
logf("mxx: Device Init");
|
||||||
|
|
||||||
|
/* State left behind by m:robe 500i original firmware */
|
||||||
|
M66591_TRN_CTRL = 0x8001; /* External 48 MHz clock */
|
||||||
|
M66591_TRN_LNSTAT = 0x0040; /* "Reserved. Set it to '1'." */
|
||||||
|
|
||||||
|
M66591_PIN_CFG0 = 0x0000;
|
||||||
|
M66591_PIN_CFG1 = 0x8000; /* Drive Current: 3.3V setting */
|
||||||
|
M66591_PIN_CFG2 = 0x0000;
|
||||||
|
|
||||||
|
M66591_INTCFG_MAIN = 0x0000; /* All Interrupts Disable for now */
|
||||||
|
M66591_INTCFG_OUT = 0x0000; /* Sense is edge, polarity is low */
|
||||||
|
M66591_INTCFG_RDY = 0x0000;
|
||||||
|
M66591_INTCFG_NRDY = 0x0000;
|
||||||
|
M66591_INTCFG_EMP = 0x0000;
|
||||||
|
|
||||||
|
M66591_INTSTAT_MAIN = 0;
|
||||||
|
M66591_INTSTAT_RDY = 0;
|
||||||
|
M66591_INTSTAT_NRDY = 0;
|
||||||
|
M66591_INTSTAT_EMP = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fully enable driver */
|
||||||
|
void usb_attach(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Reset Endpoint states */
|
||||||
|
for(i=0; i<USB_NUM_ENDPOINTS; i++) {
|
||||||
|
M66591_eps[i].dir = -1;
|
||||||
|
M66591_eps[i].buf = (char *) 0;
|
||||||
|
M66591_eps[i].length = 0;
|
||||||
|
M66591_eps[i].count = 0;
|
||||||
|
M66591_eps[i].waiting = false;
|
||||||
|
M66591_eps[i].busy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Issue a h/w reset */
|
||||||
|
usb_init_device();
|
||||||
|
usb_drv_init();
|
||||||
|
|
||||||
|
/* USB Attach Process: This follows the flow diagram in the M66591GP
|
||||||
|
* Reference Manual Rev 1.00, p. 77 */
|
||||||
|
|
||||||
|
#if defined(HISPEED)
|
||||||
|
/* Run Hi-Speed */
|
||||||
|
M66591_TRN_CTRL |= 1<<7;
|
||||||
|
#else
|
||||||
|
/* Run Full-Speed */
|
||||||
|
M66591_TRN_CTRL &= ~(1<<7);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Enable oscillation buffer */
|
||||||
|
M66591_TRN_CTRL |= (1<<13);
|
||||||
|
|
||||||
|
udelay(1500);
|
||||||
|
|
||||||
|
/* Enable reference clock, PLL */
|
||||||
|
M66591_TRN_CTRL |= (3<<11);
|
||||||
|
|
||||||
|
udelay(9);
|
||||||
|
|
||||||
|
/* Enable internal clock supply */
|
||||||
|
M66591_TRN_CTRL |= (1<<10);
|
||||||
|
|
||||||
|
/* Disable PIPE ready interrupts */
|
||||||
|
M66591_INTCFG_RDY = 0;
|
||||||
|
|
||||||
|
/* Disable PIPE not-ready interrupts */
|
||||||
|
M66591_INTCFG_NRDY = 0;
|
||||||
|
|
||||||
|
/* Disable PIPE empyt/size error interrupts */
|
||||||
|
M66591_INTCFG_EMP = 0;
|
||||||
|
|
||||||
|
/* Enable all interrupts except NOT READY, RESUME, and VBUS */
|
||||||
|
M66591_INTCFG_MAIN = 0x1DFF;
|
||||||
|
|
||||||
|
pipe_c_select(0, false);
|
||||||
|
|
||||||
|
/* Enable continuous transfer mode on the DCP */
|
||||||
|
M66591_DCP_CNTMD |= (1<<8);
|
||||||
|
|
||||||
|
/* Set the threshold that the PHY will automatically transmit from EP0 */
|
||||||
|
M66591_DCP_CTRLEN = 128;
|
||||||
|
|
||||||
|
pipe_handshake(0, PIPE_SHAKE_NAK);
|
||||||
|
|
||||||
|
/* Set the Max packet size to 64 */
|
||||||
|
M66591_DCP_MXPKSZ = 64;
|
||||||
|
|
||||||
|
/* Attach notification to PC (D+ pull-up) */
|
||||||
|
M66591_TRN_CTRL |= (1<<4);
|
||||||
|
|
||||||
|
logf("mxx: attached");
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_drv_exit(void) {
|
||||||
|
/* USB Detach Process: This follows the flow diagram in the M66591GP
|
||||||
|
* Reference Manual Rev 1.00, p. 78.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Detach notification to PC (disable D+ pull-up) */
|
||||||
|
M66591_TRN_CTRL &= ~(1<<4);
|
||||||
|
|
||||||
|
/* Software reset */
|
||||||
|
M66591_TRN_CTRL &= ~0x01;
|
||||||
|
|
||||||
|
/* Disable internal clock supply */
|
||||||
|
M66591_TRN_CTRL &= ~(1<<10);
|
||||||
|
udelay(3);
|
||||||
|
|
||||||
|
/* Disable PLL */
|
||||||
|
M66591_TRN_CTRL &= ~(1<<11);
|
||||||
|
udelay(3);
|
||||||
|
|
||||||
|
/* Disable internal reference clock */
|
||||||
|
M66591_TRN_CTRL &= ~(1<<12);
|
||||||
|
udelay(3);
|
||||||
|
|
||||||
|
/* Disable oscillation buffer, reenable USB operation */
|
||||||
|
M66591_TRN_CTRL &= ~(1<<13);
|
||||||
|
|
||||||
|
M66591_TRN_CTRL |= 0x01;
|
||||||
|
|
||||||
|
logf("mxx: detached");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function begins a transmit (on an IN endpoint), it should not block
|
||||||
|
* so the actual transmit is done in the interrupt handler.
|
||||||
|
*/
|
||||||
|
int usb_drv_send_nonblocking(int endpoint, void* ptr, int length)
|
||||||
|
{
|
||||||
|
/* The last arguement for queue specifies the dir of data (true==send) */
|
||||||
|
return mxx_queue(endpoint, ptr, length, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function begins a transmit (on an IN endpoint), it does not block
|
||||||
|
* so the actual transmit is done in the interrupt handler.
|
||||||
|
*/
|
||||||
|
int usb_drv_send(int endpoint, void* ptr, int length)
|
||||||
|
{
|
||||||
|
/* The last arguement for queue specifies the dir of data (true==send) */
|
||||||
|
return mxx_queue(endpoint, ptr, length, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function begins a receive (on an OUT endpoint), it should not block
|
||||||
|
* so the actual receive is done in the interrupt handler.
|
||||||
|
*/
|
||||||
|
int usb_drv_recv(int endpoint, void* ptr, int length)
|
||||||
|
{
|
||||||
|
/* Last arguement for queue specifies the dir of data (false==receive) */
|
||||||
|
return mxx_queue(endpoint, ptr, length, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function checks the reset handshake speed status
|
||||||
|
* (Fullspeed or Highspeed)
|
||||||
|
*/
|
||||||
|
int usb_drv_port_speed(void)
|
||||||
|
{
|
||||||
|
int handshake = (M66591_HSFS & 0xFF);
|
||||||
|
|
||||||
|
if( handshake == 0x02) {
|
||||||
|
return 0; /* Handshook at Full-Speed */
|
||||||
|
} else if( handshake == 0x03) {
|
||||||
|
return 1; /* Handshook at Hi-Speed */
|
||||||
|
} else {
|
||||||
|
return -1; /* Error, handshake may not be complete */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function checks if the endpoint is stalled (error). I am not sure what
|
||||||
|
* the "in" variable is intended for.
|
||||||
|
*/
|
||||||
|
bool usb_drv_stalled(int endpoint,bool in)
|
||||||
|
{
|
||||||
|
(void) in;
|
||||||
|
|
||||||
|
bool stalled = (*(pipe_ctrl_addr(endpoint)) & (0x02)) ? true : false;
|
||||||
|
|
||||||
|
logf("mxx: stall?: %s ep: %d", stalled ? "true" : "false", endpoint);
|
||||||
|
|
||||||
|
if(stalled) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function stalls/unstalls the endpoint. Stalls only happen on error so
|
||||||
|
* if the endpoint is functioning properly this should not be called. I am
|
||||||
|
* not sure what the "in" variable is intended for.
|
||||||
|
*/
|
||||||
|
void usb_drv_stall(int endpoint, bool stall,bool in)
|
||||||
|
{
|
||||||
|
(void) in;
|
||||||
|
|
||||||
|
logf("mxx: stall - ep: %d", endpoint);
|
||||||
|
|
||||||
|
if(stall) {
|
||||||
|
/* Stall the pipe (host needs to intervene/error) */
|
||||||
|
pipe_handshake(endpoint, PIPE_SHAKE_STALL);
|
||||||
|
} else {
|
||||||
|
/* Setting this to a NAK, not sure if it is appropriate */
|
||||||
|
pipe_handshake(endpoint, PIPE_SHAKE_NAK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* !!!!!!!!!!This function is likely incomplete!!!!!!!!!!!!!! */
|
||||||
|
void usb_drv_cancel_all_transfers(void)
|
||||||
|
{
|
||||||
|
int endpoint;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
logf("mxx: %s", __func__);
|
||||||
|
|
||||||
|
flags = disable_irq_save();
|
||||||
|
for (endpoint = 0; endpoint < USB_NUM_ENDPOINTS; endpoint++) {
|
||||||
|
if (M66591_eps[endpoint].buf) {
|
||||||
|
M66591_eps[endpoint].buf = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_irq(flags);
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
/* define this if you use an ATA controller */
|
/* define this if you use an ATA controller */
|
||||||
#define CONFIG_STORAGE STORAGE_ATA
|
#define CONFIG_STORAGE STORAGE_ATA
|
||||||
|
|
||||||
|
/* Define this to add support for ATA DMA */
|
||||||
|
//#define HAVE_ATA_DMA
|
||||||
|
|
||||||
/* define this if you have a bitmap LCD display */
|
/* define this if you have a bitmap LCD display */
|
||||||
#define HAVE_LCD_BITMAP
|
#define HAVE_LCD_BITMAP
|
||||||
|
|
||||||
|
@ -114,6 +117,19 @@
|
||||||
#define HAVE_TOUCHSCREEN
|
#define HAVE_TOUCHSCREEN
|
||||||
#define HAVE_BUTTON_DATA
|
#define HAVE_BUTTON_DATA
|
||||||
|
|
||||||
|
/* M66591 register base */
|
||||||
|
#define M66591_BASE 0x60000000
|
||||||
|
|
||||||
|
/* enable these for the usb stack */
|
||||||
|
#define CONFIG_USBOTG USBOTG_M66591
|
||||||
|
#define USE_ROCKBOX_USB
|
||||||
|
#define HAVE_USBSTACK
|
||||||
|
#define USB_STORAGE
|
||||||
|
/* usb stack and driver settings */
|
||||||
|
#define USB_NUM_ENDPOINTS 7
|
||||||
|
#define USB_VENDOR_ID 0x07b4
|
||||||
|
#define USB_PRODUCT_ID 0x0281
|
||||||
|
|
||||||
/* define this if the target has volume keys which can be used in the lists */
|
/* define this if the target has volume keys which can be used in the lists */
|
||||||
#define HAVE_VOLUME_IN_LIST
|
#define HAVE_VOLUME_IN_LIST
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,7 @@ Lyre prototype 1*/
|
||||||
#define RTC_JZ47XX 16 /* Ingenic Jz47XX */
|
#define RTC_JZ47XX 16 /* Ingenic Jz47XX */
|
||||||
|
|
||||||
/* USB On-the-go */
|
/* USB On-the-go */
|
||||||
|
#define USBOTG_M66591 6591 /* M:Robe 500 */
|
||||||
#define USBOTG_ISP1362 1362 /* iriver H300 */
|
#define USBOTG_ISP1362 1362 /* iriver H300 */
|
||||||
#define USBOTG_ISP1583 1583 /* Creative Zen Vision:M */
|
#define USBOTG_ISP1583 1583 /* Creative Zen Vision:M */
|
||||||
#define USBOTG_M5636 5636 /* iAudio X5 */
|
#define USBOTG_M5636 5636 /* iAudio X5 */
|
||||||
|
@ -775,7 +776,7 @@ Lyre prototype 1*/
|
||||||
#elif CONFIG_USBOTG == USBOTG_JZ4740
|
#elif CONFIG_USBOTG == USBOTG_JZ4740
|
||||||
#define USB_HAS_BULK
|
#define USB_HAS_BULK
|
||||||
#define USB_HAS_INTERRUPT
|
#define USB_HAS_INTERRUPT
|
||||||
#elif defined(CPU_TCC780X) || defined(CPU_TCC77X)
|
#elif defined(CPU_TCC780X) || defined(CPU_TCC77X) || defined(MROBE_500)
|
||||||
#define USB_HAS_BULK
|
#define USB_HAS_BULK
|
||||||
#endif /* CONFIG_USBOTG */
|
#endif /* CONFIG_USBOTG */
|
||||||
|
|
||||||
|
|
102
firmware/export/m66591.h
Normal file
102
firmware/export/m66591.h
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id: $
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 by Karl Kurbjun
|
||||||
|
*
|
||||||
|
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define M66591_REG(addr) (*(volatile unsigned short *) \
|
||||||
|
((unsigned char *) M66591_BASE + (addr)) )
|
||||||
|
|
||||||
|
/* Interrupt handler routine, visible for target handler */
|
||||||
|
void USB_DEVICE(void);
|
||||||
|
|
||||||
|
/* Register offsets */
|
||||||
|
#define M66591_TRN_CTRL M66591_REG(0x00) /* pg 14 */
|
||||||
|
#define M66591_TRN_LNSTAT M66591_REG(0x02) /* pg 16 */
|
||||||
|
|
||||||
|
#define M66591_HSFS M66591_REG(0x04) /* pg 17 */
|
||||||
|
#define M66591_TESTMODE M66591_REG(0x06) /* pg 18 */
|
||||||
|
|
||||||
|
#define M66591_PIN_CFG0 M66591_REG(0x08) /* pg 19 */
|
||||||
|
#define M66591_PIN_CFG1 M66591_REG(0x0A) /* pg 20 */
|
||||||
|
#define M66591_PIN_CFG2 M66591_REG(0x0C) /* pg 21 */
|
||||||
|
|
||||||
|
#define M66591_CPORT M66591_REG(0x14) /* pg 23 */
|
||||||
|
#define M66591_DPORT M66591_REG(0x18) /* pg 24 */
|
||||||
|
|
||||||
|
#define M66591_DCP_CTRLEN M66591_REG(0x26) /* pg 25 */
|
||||||
|
|
||||||
|
#define M66591_CPORT_CTRL0 M66591_REG(0x28) /* pg 26 */
|
||||||
|
#define M66591_CPORT_CTRL1 M66591_REG(0x2C) /* pg 28 */
|
||||||
|
#define M66591_CPORT_CTRL2 M66591_REG(0x2E) /* pg 30 */
|
||||||
|
|
||||||
|
#define M66591_DPORT_CTRL0 M66591_REG(0x30) /* pg 31 */
|
||||||
|
#define M66591_DPORT_CTRL1 M66591_REG(0x34) /* pg 34 */
|
||||||
|
#define M66591_DPORT_CTRL2 M66591_REG(0x36) /* pg 36 */
|
||||||
|
|
||||||
|
#define M66591_INTCFG_MAIN M66591_REG(0x40) /* pg 37 */
|
||||||
|
#define M66591_INTCFG_OUT M66591_REG(0x42) /* pg 40 */
|
||||||
|
#define M66591_INTCFG_RDY M66591_REG(0x44) /* pg 41 */
|
||||||
|
#define M66591_INTCFG_NRDY M66591_REG(0x48) /* pg 42 */
|
||||||
|
#define M66591_INTCFG_EMP M66591_REG(0x4C) /* pg 43 */
|
||||||
|
|
||||||
|
#define M66591_INTSTAT_MAIN M66591_REG(0x60) /* pg 44 */
|
||||||
|
#define M66591_INTSTAT_RDY M66591_REG(0x64) /* pg 48 */
|
||||||
|
#define M66591_INTSTAT_NRDY M66591_REG(0x68) /* pg 50 */
|
||||||
|
#define M66591_INTSTAT_EMP M66591_REG(0x6C) /* pg 53 */
|
||||||
|
|
||||||
|
#define M66591_USB_ADDRESS M66591_REG(0x74) /* pg 56 */
|
||||||
|
|
||||||
|
#define M66591_USB_REQ0 M66591_REG(0x78) /* pg 57 */
|
||||||
|
#define M66591_USB_REQ1 M66591_REG(0x7A) /* pg 58 */
|
||||||
|
#define M66591_USB_REQ2 M66591_REG(0x7C) /* pg 59 */
|
||||||
|
#define M66591_USB_REQ3 M66591_REG(0x7E) /* pg 60 */
|
||||||
|
|
||||||
|
#define M66591_DCP_CNTMD M66591_REG(0x82) /* pg 61 */
|
||||||
|
#define M66591_DCP_MXPKSZ M66591_REG(0x84) /* pg 62 */
|
||||||
|
#define M66591_DCPCTRL M66591_REG(0x88) /* pg 63 */
|
||||||
|
|
||||||
|
#define M66591_PIPE_CFGSEL M66591_REG(0x8C) /* pg 65 */
|
||||||
|
#define M66591_PIPE_CFGWND M66591_REG(0x90) /* pg 66 */
|
||||||
|
|
||||||
|
#define M66591_PIPECTRL1 M66591_REG(0xA0) /* pg 69 */
|
||||||
|
#define M66591_PIPECTRL2 M66591_REG(0xA2) /* pg 69 */
|
||||||
|
#define M66591_PIPECTRL3 M66591_REG(0xA4) /* pg 69 */
|
||||||
|
#define M66591_PIPECTRL4 M66591_REG(0xA6) /* pg 69 */
|
||||||
|
#define M66591_PIPECTRL5 M66591_REG(0xA8) /* pg 71 */
|
||||||
|
#define M66591_PIPECTRL6 M66591_REG(0xAA) /* pg 71 */
|
||||||
|
|
||||||
|
/* These defines are used for CTRL register handshake setup
|
||||||
|
* They are used on the following registers:
|
||||||
|
* DCPCTRL and PIPECTRL(1-6)
|
||||||
|
*/
|
||||||
|
#define PIPE_SHAKE_NAK 0x00
|
||||||
|
#define PIPE_SHAKE_BUF 0x01
|
||||||
|
#define PIPE_SHAKE_STALL 0x02
|
||||||
|
|
||||||
|
/* These defines are used for the control transfer stage status */
|
||||||
|
#define CTRL_IDLE 0x00 /* Idle Stage */
|
||||||
|
#define CTRL_RTDS 0x01 /* Read transfer data stage */
|
||||||
|
#define CTRL_RTSS 0x02 /* Read transfer status stage */
|
||||||
|
#define CTRL_WTDS 0x03 /* Write transfer data stage */
|
||||||
|
#define CTRL_WTSS 0x04 /* Write transfer status stage */
|
||||||
|
#define CTRL_WTND 0x05 /* Write transfer no data stage */
|
||||||
|
#define CTRL_TRER 0x06 /* Transmit error stage */
|
||||||
|
|
|
@ -138,9 +138,20 @@ SECTIONS
|
||||||
. += TTB_SIZE;
|
. += TTB_SIZE;
|
||||||
} > DRAM
|
} > DRAM
|
||||||
|
|
||||||
|
/* The LCD buffer should be at the end of memory to protect against
|
||||||
|
* overflowing something else when the YUV blitter is fudging the screen
|
||||||
|
* size.
|
||||||
|
*/
|
||||||
|
|
||||||
.lcdbuffer (NOLOAD) :
|
.lcdbuffer (NOLOAD) :
|
||||||
{
|
{
|
||||||
_lcdbuf = .;
|
_lcdbuf = .;
|
||||||
. += LCD_BUFFER_SIZE;
|
. += LCD_BUFFER_SIZE;
|
||||||
} > DRAM
|
} > DRAM
|
||||||
|
|
||||||
|
.lcdbuffer2 (NOLOAD) :
|
||||||
|
{
|
||||||
|
_lcdbuf2 = .;
|
||||||
|
. += LCD_BUFFER_SIZE;
|
||||||
|
} > DRAM
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ start:
|
||||||
strhi r5, [r3], #4
|
strhi r5, [r3], #4
|
||||||
bhi 1b
|
bhi 1b
|
||||||
#endif
|
#endif
|
||||||
#endif /* !BOOTLOADER,!STUB */
|
#endif /* !STUB */
|
||||||
|
|
||||||
|
|
||||||
/* Initialise bss section to zero */
|
/* Initialise bss section to zero */
|
||||||
|
@ -113,26 +113,6 @@ stackmunge:
|
||||||
/* Switch to supervisor mode (no IRQ) */
|
/* Switch to supervisor mode (no IRQ) */
|
||||||
msr cpsr_c, #0xd3
|
msr cpsr_c, #0xd3
|
||||||
ldr sp, =stackend
|
ldr sp, =stackend
|
||||||
|
|
||||||
#if defined(BOOTLOADER) && !defined(CREATIVE_ZVx)
|
|
||||||
/* get the high part of our execute address */
|
|
||||||
ldr r2, =0xffffff00
|
|
||||||
and r4, pc, r2
|
|
||||||
|
|
||||||
/* Copy bootloader to safe area - 0x01900000 */
|
|
||||||
mov r5, #0x01900000
|
|
||||||
ldr r6, = _dataend
|
|
||||||
sub r0, r6, r5 /* length of loader */
|
|
||||||
add r0, r4, r0 /* r0 points to start of loader */
|
|
||||||
1:
|
|
||||||
cmp r5, r6
|
|
||||||
ldrcc r2, [r4], #4
|
|
||||||
strcc r2, [r5], #4
|
|
||||||
bcc 1b
|
|
||||||
|
|
||||||
ldr pc, =start_loc /* jump to the relocated start_loc: */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
start_loc:
|
start_loc:
|
||||||
bl main
|
bl main
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
#include "tsc2100.h"
|
#include "tsc2100.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
unsigned short current_bat2 = 3910;
|
unsigned short current_bat2 = 4200;
|
||||||
unsigned short current_aux = 3910;
|
unsigned short current_aux = 4200;
|
||||||
static unsigned short current_voltage = 3910;
|
static unsigned short current_voltage = 4200;
|
||||||
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
||||||
{
|
{
|
||||||
3450
|
3450
|
||||||
|
@ -69,7 +69,7 @@ unsigned int battery_adc_voltage(void)
|
||||||
current_aux=((short)((int)(aux<<10)/4096*6*2.5));
|
current_aux=((short)((int)(aux<<10)/4096*6*2.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TIME_BEFORE(last_tick+2*HZ, current_tick))
|
if (TIME_BEFORE(last_tick+2*HZ, current_tick) || last_tick==0)
|
||||||
{
|
{
|
||||||
tsadc=tsc2100_readreg(TSADC_PAGE, TSADC_ADDRESS);
|
tsadc=tsc2100_readreg(TSADC_PAGE, TSADC_ADDRESS);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* \/ \/ \/ \/ \/
|
* \/ \/ \/ \/ \/
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007 by Karl Kurbjun
|
* Copyright (C) 2007, 2009 by Karl Kurbjun
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -18,42 +18,60 @@
|
||||||
* KIND, either express or implied.
|
* KIND, either express or implied.
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
#define LOGF_ENABLE
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "logf.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "kernel.h"
|
|
||||||
#include "ata.h"
|
|
||||||
#include "usb.h"
|
|
||||||
#include "usb-target.h"
|
|
||||||
|
|
||||||
#define USB_RST_ASSERT
|
#include "m66591.h"
|
||||||
#define USB_RST_DEASSERT
|
|
||||||
|
|
||||||
#define USB_VPLUS_PWR_ASSERT
|
void usb_init_device(void) {
|
||||||
#define USB_VPLUS_PWR_DEASSERT
|
logf("mxx: SOC Init");
|
||||||
|
|
||||||
#define USB_UNIT_IS_PRESENT USB_EXTRACTED
|
/* The EMIF timing that is currently used may not be apropriate when the
|
||||||
|
* device is boosted. The following values were used with sucess too:
|
||||||
|
* IO_EMIF_CS4CTRL1 = 0x66AB;
|
||||||
|
* IO_EMIF_CS4CTRL2 = 0x4220;
|
||||||
|
*/
|
||||||
|
IO_EMIF_CS4CTRL1 = 0x2245;
|
||||||
|
IO_EMIF_CS4CTRL2 = 0x4110;
|
||||||
|
|
||||||
/* The usb detect is one pin to the cpu active low */
|
IO_GIO_DIR0 &= ~(1<<2);
|
||||||
inline int usb_detect(void)
|
IO_GIO_INV0 &= ~(1<<2);
|
||||||
{
|
IO_GIO_FSEL0 &= ~(0x03);
|
||||||
return USB_UNIT_IS_PRESENT;
|
|
||||||
|
/* Drive the reset pin low */
|
||||||
|
IO_GIO_BITCLR0 = 1<<2;
|
||||||
|
|
||||||
|
/* Wait a bit */
|
||||||
|
udelay(3);
|
||||||
|
|
||||||
|
/* Release the reset (drive it high) */
|
||||||
|
IO_GIO_BITSET0 = 1<<2;
|
||||||
|
|
||||||
|
udelay(300);
|
||||||
|
|
||||||
|
IO_GIO_DIR0 |= 1<<3;
|
||||||
|
IO_GIO_INV0 &= ~(1<<3);
|
||||||
|
IO_GIO_IRQPORT |= 1<<3;
|
||||||
|
|
||||||
|
/* Enable the MXX interrupt */
|
||||||
|
IO_INTC_EINT1 |= (1<<8); /* IRQ_GIO3 */
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_init_device(void)
|
/* This is the initial interupt handler routine for the USB controller */
|
||||||
{
|
void GIO3 (void) {
|
||||||
// ata_enable(true);
|
/* Clear the interrupt, this is critical to do before running the full
|
||||||
|
* handler otherwise you might miss an interrupt and everything will stop
|
||||||
|
* working.
|
||||||
|
*
|
||||||
|
* The M66591 interrupt line is attached to GPIO3.
|
||||||
|
*/
|
||||||
|
IO_INTC_IRQ1 = (1<<8);
|
||||||
|
|
||||||
|
/* Start the full handler which is located in the driver */
|
||||||
|
USB_DEVICE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_enable(bool on)
|
|
||||||
{
|
|
||||||
if (on)
|
|
||||||
{
|
|
||||||
USB_VPLUS_PWR_ASSERT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
USB_VPLUS_PWR_DEASSERT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
#ifdef CREATIVE_ZVx
|
#ifdef CREATIVE_ZVx
|
||||||
#include "dma-target.h"
|
#include "dma-target.h"
|
||||||
|
#include "usb-mr500.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define default_interrupt(name) \
|
#define default_interrupt(name) \
|
||||||
|
@ -308,3 +309,14 @@ void set_cpu_frequency(long frequency)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This function is pretty crude. It is not acurate to a usec, but errors on
|
||||||
|
* longer.
|
||||||
|
*/
|
||||||
|
void udelay(int usec) {
|
||||||
|
volatile int temp=usec*(175000/200);
|
||||||
|
|
||||||
|
while(temp) {
|
||||||
|
temp--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,4 +28,6 @@
|
||||||
#define CPUFREQ_NORMAL 87500000
|
#define CPUFREQ_NORMAL 87500000
|
||||||
#define CPUFREQ_MAX 175000000
|
#define CPUFREQ_MAX 175000000
|
||||||
|
|
||||||
|
void udelay(int usec);
|
||||||
|
|
||||||
#endif /* SYSTEM_TARGET_H */
|
#endif /* SYSTEM_TARGET_H */
|
||||||
|
|
|
@ -48,7 +48,8 @@
|
||||||
/* Conditions under which we want the entire driver */
|
/* Conditions under which we want the entire driver */
|
||||||
#if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \
|
#if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \
|
||||||
(defined(TOSHIBA_GIGABEAT_S) && defined(USE_ROCKBOX_USB) && defined(USB_ENABLE_STORAGE)) || \
|
(defined(TOSHIBA_GIGABEAT_S) && defined(USE_ROCKBOX_USB) && defined(USB_ENABLE_STORAGE)) || \
|
||||||
(defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx) || \
|
(defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx)) || \
|
||||||
|
(defined(HAVE_USBSTACK) && (defined(OLYMPUS_MROBE_500)) || \
|
||||||
defined(CPU_TCC77X) || defined(CPU_TCC780X))) || \
|
defined(CPU_TCC77X) || defined(CPU_TCC780X))) || \
|
||||||
(CONFIG_USBOTG == USBOTG_JZ4740)
|
(CONFIG_USBOTG == USBOTG_JZ4740)
|
||||||
#define USB_FULL_INIT
|
#define USB_FULL_INIT
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue