From 02385cb5b02ecd13ee63fb636a8ed65071407b01 Mon Sep 17 00:00:00 2001 From: Karl Kurbjun Date: Mon, 2 Nov 2009 04:37:57 +0000 Subject: M:Robe 500/M66591 USB improvements: Interrupts now work, a bug in odd-length transfers has been fixed. Buffers that are not initially short aligned are also now supported. Enable USB HID mouse mode. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23483 a1c6a512-1295-4272-9138-f99709370657 --- apps/keymaps/keymap-touchscreen.c | 28 ++- firmware/drivers/m66591.c | 188 ++++++++++++++------- firmware/export/config-mrobe500.h | 3 +- firmware/export/usb.h | 8 + .../target/arm/tms320dm320/mrobe-500/usb-mr500.c | 38 +++-- firmware/target/arm/tms320dm320/system-dm320.c | 8 +- 6 files changed, 193 insertions(+), 80 deletions(-) diff --git a/apps/keymaps/keymap-touchscreen.c b/apps/keymaps/keymap-touchscreen.c index 74673ccb20..e7cf87a7a1 100644 --- a/apps/keymaps/keymap-touchscreen.c +++ b/apps/keymaps/keymap-touchscreen.c @@ -310,6 +310,27 @@ static const struct button_mapping button_context_usb_hid_mode_browser[] = { LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID) }; /* button_context_usb_hid_mode_browser */ + +#ifdef HAVE_USB_HID_MOUSE +static const struct button_mapping button_context_usb_hid_mode_mouse[] = { + { ACTION_USB_HID_MOUSE_UP, BUTTON_TOPMIDDLE, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_UP_REP, BUTTON_TOPMIDDLE|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_DOWN, BUTTON_BOTTOMMIDDLE, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_DOWN_REP, BUTTON_BOTTOMMIDDLE|BUTTON_REPEAT,BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_LEFT, BUTTON_MIDLEFT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_LEFT_REP, BUTTON_MIDLEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_RIGHT, BUTTON_MIDRIGHT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_RIGHT_REP, BUTTON_MIDRIGHT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_BUTTON_LEFT, BUTTON_CENTER, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_BUTTON_LEFT_REL, BUTTON_CENTER|BUTTON_REL, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_UP, BUTTON_TOPRIGHT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_UP, BUTTON_TOPRIGHT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_DOWN, BUTTON_BOTTOMRIGHT, BUTTON_NONE }, + { ACTION_USB_HID_MOUSE_WHEEL_SCROLL_DOWN, BUTTON_BOTTOMRIGHT|BUTTON_REPEAT, BUTTON_NONE }, + + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_USB_HID) +}; /* button_context_usb_hid_mode_mouse */ +#endif #endif const struct button_mapping* get_context_mapping(int context) @@ -373,8 +394,13 @@ const struct button_mapping* get_context_mapping(int context) return button_context_usb_hid_mode_presentation; case CONTEXT_USB_HID_MODE_BROWSER: return button_context_usb_hid_mode_browser; +#ifdef HAVE_USB_HID_MOUSE + case CONTEXT_USB_HID_MODE_MOUSE: + return button_context_usb_hid_mode_mouse; #endif - +#endif + default: + return button_context_standard; } return button_context_standard; } diff --git a/firmware/drivers/m66591.c b/firmware/drivers/m66591.c index 2ce121a263..1197485cd2 100644 --- a/firmware/drivers/m66591.c +++ b/firmware/drivers/m66591.c @@ -19,7 +19,7 @@ * KIND, either express or implied. * ****************************************************************************/ -#define LOGF_ENABLE +//#define LOGF_ENABLE #include "system.h" #include "config.h" @@ -47,9 +47,10 @@ */ #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). +/* Right now sending blocks till the full transfer has completed. The driver + * will work without USB_TRAN_BLOCK set, but it is more than 50% slower. + * The driver is more "Proper" without USB_TRAN_BLOCK defined so if you start + * having freezeups or trouble using USB undefine this option. */ #define USB_TRAN_BLOCK @@ -69,7 +70,8 @@ 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); +static int mxx_queue(int endpoint, void * ptr, int length, bool send, + bool wait); struct M66591_epstat { unsigned char dir; /* endpoint direction */ @@ -91,6 +93,15 @@ static volatile unsigned short * pipe_ctrl_addr(int pipe) { } } +static void pipe_init(int pipe) { + volatile unsigned short *pipe_cfg; + pipe_cfg = pipe_ctrl_addr(pipe); + + *pipe_cfg |= 1<<9; /* ACLR */ + *pipe_cfg &= ~(1<<9); /* Force de-assertion */ + *pipe_cfg |= 1<<8; /* SQCLR */ +} + /* This function sets the pipe/endpoint handshake */ static void pipe_handshake(int pipe, int handshake) { handshake&=0x03; @@ -125,7 +136,10 @@ static int pipe_buffer_size (int pipe) { return 256; case 1: case 2: - return 1024; + if(M66591_PIPE_CFGWND & (1<<9) ) + return 1024; + else + return 512; case 3: case 4: return 512; @@ -206,7 +220,7 @@ static void transfer_complete(int 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); + M66591_eps[endpoint].count); } /* This is the main transmit routine that is typically called from the interrupt @@ -250,7 +264,8 @@ static int mxx_transmit_receive(int endpoint) { length = M66591_eps[endpoint].length; #else int bufsize=pipe_buffer_size(endpoint); - length=MIN(M66591_eps[endpoint].length, bufsize); + length=MIN(M66591_eps[endpoint].length - M66591_eps[endpoint].count, + bufsize); #endif /* Calculate the position in the buffer, all transfers should be 2-byte @@ -259,32 +274,70 @@ static int mxx_transmit_receive(int endpoint) { 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 that 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))){}; + /* Check if the buffer is alligned */ + if( LIKELY(((int)ptrs) & 0x01) == 0 ) + { + /* Start sending data in 16-bit words (fast) */ + for (i = 0; i < (length>>1); i++) { +#if defined(USB_TRAN_BLOCK) + /* This wait is dangerous in the event that 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))){}; +#endif - 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++; + 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); + 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); + else + { + /* The buffer is mis-aligned - data needs to be organized first. + * This is slower than the above method. + */ + unsigned short sbuf; + unsigned char *ptrc = (unsigned char*)ptrs; + + /* Start sending data in 16-bit words */ + for (i = 0; i < (length>>1); i++) { +#if defined(USB_TRAN_BLOCK) + /* This wait is dangerous in the event that 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))){}; +#endif + + /* These are mis-aligned accesses so the data nees to be + * arranged. + */ + sbuf = (*(ptrc+1) << 8) | *ptrc; + ptrc += 2; + + M66591_CPORT = sbuf; + 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 = *ptrc; + M66591_eps[endpoint].count++; + } } /* If the transfer is complete set up interrupts to notify when FIFO is @@ -302,6 +355,12 @@ static int mxx_transmit_receive(int endpoint) { /* There is still data to transfer, make sure READY is enabled */ M66591_INTCFG_RDY |= 1 << endpoint; } + + /* 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) | ((length == 0) << 14); + } } else { /* Read data from FIFO */ @@ -366,8 +425,17 @@ static int mxx_transmit_receive(int endpoint) { /* 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. + * + * The functionality for wait needs to be added. Currently the driver is + * always used in a blocking mode(USB_TRAN_BLOCK) so it is not required. */ -static int mxx_queue(int endpoint, void * ptr, int length, bool send) { +static int mxx_queue(int endpoint, void * ptr, int length, bool send, + bool wait) +{ +#if defined(USB_TRAN_BLOCK) && !defined(LOGF_ENABLE) + (void) wait; +#endif + /* Disable IRQs */ int flags = disable_irq_save(); @@ -384,7 +452,8 @@ static int mxx_queue(int endpoint, void * ptr, int length, bool send) { M66591_eps[endpoint].dir=send; M66591_eps[endpoint].waiting=true; - logf("mxx: queue ep %d %s, len: %d", endpoint, send ? "out" : "in", length); + logf("mxx: queue ep %d %s, len: %d, wait: %d", + endpoint, send ? "out" : "in", length, wait); /* Pick the pipe that communications are happening on */ pipe_c_select(endpoint, send); @@ -436,9 +505,10 @@ static int mxx_queue(int endpoint, void * ptr, int length, bool send) { * 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) __attribute__ ((section(".icode"))); void USB_DEVICE(void) { int pipe_restore=M66591_CPORT_CTRL0; - logf("mxx: INT BEGIN tick: %d\n", (int) current_tick); + logf("\nmxx: INT BEGIN tick: %d", (int) current_tick); logf("mxx: sMAIN0: 0x%04x, sRDY: 0x%04x", M66591_INTSTAT_MAIN, M66591_INTSTAT_RDY); @@ -548,7 +618,7 @@ void USB_DEVICE(void) { /* Restore the pipe state before the interrupt occured */ M66591_CPORT_CTRL0=pipe_restore; - logf("\nmxx: INT END"); + logf("mxx: INT END\n"); } /******************************************************************************* @@ -576,7 +646,7 @@ int usb_drv_request_endpoint(int type, int dir) { if (type == USB_ENDPOINT_XFER_BULK) { /* Enable double buffer mode (only used for ep 1 and 2) */ - pipecfg |= 1<<9; + pipecfg |= 1<<9 | 1<<8; /* Bulk endpoints must be between 1 and 4 inclusive */ ep=1; @@ -591,6 +661,8 @@ int usb_drv_request_endpoint(int type, int dir) { } else if (type == USB_ENDPOINT_XFER_INT) { ep=5; + pipecfg |= 1<<13; + while(M66591_eps[ep].busy && ep++<7); /* If this reached 7 the endpoints were all busy */ @@ -612,14 +684,16 @@ int usb_drv_request_endpoint(int type, int dir) { M66591_PIPE_CFGSEL=ep; - /* Enable pipe (15) and continuous transfer mode (8) */ - pipecfg |= 1<<15 | 1<<8; + /* Enable pipe (15) */ + pipecfg |= 1<<15; pipe_handshake(ep, PIPE_SHAKE_NAK); /* Setup the flags */ M66591_PIPE_CFGWND=pipecfg; + pipe_init(ep); + logf("mxx: ep req ep#: %d config: 0x%04x", ep, M66591_PIPE_CFGWND); return ep | dir; @@ -664,24 +738,13 @@ void usb_enable(bool on) { 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; + M66591_TRN_CTRL = 0x8000; /* External 48 MHz clock */ + M66591_TRN_CTRL |=0x0001; + + M66591_INTCFG_MAIN |=0x8000; /* Enable VBUS interrupt */ } /* fully enable driver */ @@ -713,17 +776,17 @@ void usb_attach(void) { M66591_TRN_CTRL &= ~(1<<7); #endif - /* Enable oscillation buffer */ + /* Enable oscillation buffer XCKE */ M66591_TRN_CTRL |= (1<<13); udelay(1500); - /* Enable reference clock, PLL */ + /* Enable reference clock, PLL RCKE */ M66591_TRN_CTRL |= (3<<11); udelay(9); - /* Enable internal clock supply */ + /* Enable internal clock supply SCKE */ M66591_TRN_CTRL |= (1<<10); /* Disable PIPE ready interrupts */ @@ -744,7 +807,7 @@ void usb_attach(void) { M66591_DCP_CNTMD |= (1<<8); /* Set the threshold that the PHY will automatically transmit from EP0 */ - M66591_DCP_CTRLEN = 128; + M66591_DCP_CTRLEN = 256; pipe_handshake(0, PIPE_SHAKE_NAK); @@ -793,8 +856,7 @@ void usb_drv_exit(void) { */ 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); + return mxx_queue(endpoint, ptr, length, true, false); } /* This function begins a transmit (on an IN endpoint), it does not block @@ -802,8 +864,7 @@ int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) */ 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); + return mxx_queue(endpoint, ptr, length, true, true); } /* This function begins a receive (on an OUT endpoint), it should not block @@ -811,8 +872,7 @@ int usb_drv_send(int endpoint, void* ptr, int length) */ 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); + return mxx_queue(endpoint, ptr, length, false, false); } /* This function checks the reset handshake speed status diff --git a/firmware/export/config-mrobe500.h b/firmware/export/config-mrobe500.h index d9dc054524..9d04aac125 100644 --- a/firmware/export/config-mrobe500.h +++ b/firmware/export/config-mrobe500.h @@ -207,7 +207,7 @@ /* enable these for the usb stack */ #define CONFIG_USBOTG USBOTG_M66591 #define USE_ROCKBOX_USB -//#define USB_ENABLE_SERIAL + #define HAVE_USBSTACK //#define HAVE_USB_POWER //#define USBPOWER_BUTTON BUTTON_POWER @@ -216,6 +216,7 @@ #define USB_NUM_ENDPOINTS 7 #define USB_VENDOR_ID 0x07b4 #define USB_PRODUCT_ID 0x0281 +#define HAVE_USB_HID_MOUSE /* Define this if hardware supports alternate blitting */ #define HAVE_LCD_MODES LCD_MODE_RGB565 | LCD_MODE_YUV | LCD_MODE_PAL256 diff --git a/firmware/export/usb.h b/firmware/export/usb.h index c380ac518d..d432b39b14 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -98,10 +98,18 @@ enum { #ifdef HAVE_USBSTACK /* USB class drivers */ enum { +#ifdef USB_ENABLE_STORAGE USB_DRIVER_MASS_STORAGE, +#endif +#ifdef USB_ENABLE_SERIAL USB_DRIVER_SERIAL, +#endif +#ifdef USB_ENABLE_CHARGING_ONLY USB_DRIVER_CHARGING_ONLY, +#endif +#ifdef USB_ENABLE_HID USB_DRIVER_HID, +#endif USB_NUM_DRIVERS }; diff --git a/firmware/target/arm/tms320dm320/mrobe-500/usb-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/usb-mr500.c index 1fbc1ce60f..06a501179d 100644 --- a/firmware/target/arm/tms320dm320/mrobe-500/usb-mr500.c +++ b/firmware/target/arm/tms320dm320/mrobe-500/usb-mr500.c @@ -30,32 +30,44 @@ void usb_init_device(void) { logf("mxx: SOC Init"); - /* The EMIF timing that is currently used may not be apropriate when the - * device is boosted. The following values were used with sucess too: + /* The following EMIF timing values are from the OF: * IO_EMIF_CS4CTRL1 = 0x66AB; * IO_EMIF_CS4CTRL2 = 0x4220; + * + * These EMIF timing values are more agressive, but appear to work as long + * as USB_TRANS_BLOCK is defined in the USB driver: + * IO_EMIF_CS4CTRL1 = 0x2245; + * IO_EMIF_CS4CTRL2 = 0x4110; + * + * When USB_TRANS_BLOCK is not defined the USB driver does not work unless + * the values from the OF are used. */ + IO_EMIF_CS4CTRL1 = 0x2245; IO_EMIF_CS4CTRL2 = 0x4110; - IO_GIO_DIR0 &= ~(1<<2); - IO_GIO_INV0 &= ~(1<<2); - IO_GIO_FSEL0 &= ~(0x03); + /* Setup the m66591 reset signal */ + IO_GIO_DIR0 &= ~(1<<2); /* output */ + IO_GIO_INV0 &= ~(1<<2); /* non-inverted */ + IO_GIO_FSEL0 &= ~(0x03); /* normal pins */ + + /* Setup the m66591 interrupt signal */ + IO_GIO_DIR0 |= 1<<3; /* input */ + IO_GIO_INV0 &= ~(1<<3); /* non-inverted */ + IO_GIO_IRQPORT |= 1<<3; /* enable EIRQ */ + + udelay(100); /* Drive the reset pin low */ - IO_GIO_BITCLR0 = 1<<2; + IO_GIO_BITCLR0 = 1<<2; /* Wait a bit */ - udelay(3); + udelay(100); /* Release the reset (drive it high) */ - IO_GIO_BITSET0 = 1<<2; - - udelay(300); + IO_GIO_BITSET0 = 1<<2; - IO_GIO_DIR0 |= 1<<3; - IO_GIO_INV0 &= ~(1<<3); - IO_GIO_IRQPORT |= 1<<3; + udelay(500); /* Enable the MXX interrupt */ IO_INTC_EINT1 |= (1<<8); /* IRQ_GIO3 */ diff --git a/firmware/target/arm/tms320dm320/system-dm320.c b/firmware/target/arm/tms320dm320/system-dm320.c index d1f2ff1684..434b0065a5 100644 --- a/firmware/target/arm/tms320dm320/system-dm320.c +++ b/firmware/target/arm/tms320dm320/system-dm320.c @@ -102,7 +102,7 @@ static const unsigned short const irqpriority[] = IRQ_ICE,IRQ_ARMCOM_RX,IRQ_ARMCOM_TX,IRQ_RESERVED }; /* IRQ priorities, ranging from highest to lowest */ -static void (* const irqvector[])(void) = +static void (* const irqvector[])(void) __attribute__ ((section(".idata"))) = { TIMER0,TIMER1,TIMER2,TIMER3,CCD_VD0,CCD_VD1, CCD_WEN,VENC,SERIAL0,SERIAL1,EXT_HOST,DSPHINT, @@ -222,11 +222,16 @@ void system_init(void) /* setup the clocks */ IO_CLK_DIV0=0x0003; + + /* SDRAM Divide by 3 */ IO_CLK_DIV1=0x0102; IO_CLK_DIV2=0x021F; IO_CLK_DIV3=0x1FFF; IO_CLK_DIV4=0x1F00; + /* 27 MHz input clock: + * PLLA = 27*11/1 + */ IO_CLK_PLLA=0x80A0; IO_CLK_PLLB=0x80C0; @@ -286,6 +291,7 @@ void system_init(void) ttb_init(); /* Make sure everything is mapped on itself */ map_section(0, 0, 0x1000, CACHE_NONE); + /* Enable caching for RAM */ map_section(CONFIG_SDRAM_START, CONFIG_SDRAM_START, MEM, CACHE_ALL); /* enable buffered writing for the framebuffer */ -- cgit v1.2.3