From 616c98b38f6ddac0ac3dde8ec0fa248f835717e2 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Mon, 19 Jan 2009 13:41:25 +0000 Subject: USB detection changes. c200/e200: Consider USB to be powered when charger is plugged but detect USB connection by bus reset. When received, disconnect and restart the driver fully enabled. imx31: Fix hack used to make initial connect succeeded-- set PHY type before initial reset. General: Move some target code out of usb-drv-arc.c and implement it in respective usb sources and CPU headers so things stay clean. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19797 a1c6a512-1295-4272-9138-f99709370657 --- bootloader/gigabeat-s.c | 1 - firmware/export/config-c200.h | 3 + firmware/export/config-e200.h | 3 + firmware/export/config-gigabeat-s.h | 6 +- firmware/export/imx31l.h | 8 +- firmware/export/pp5020.h | 7 +- firmware/export/usb.h | 8 +- firmware/export/usb_core.h | 10 +- firmware/export/usb_drv.h | 6 +- .../target/arm/imx31/gigabeat-s/system-target.h | 8 + firmware/target/arm/imx31/gigabeat-s/usb-imx31.c | 35 ++-- firmware/target/arm/powermgmt-ascodec.c | 10 ++ firmware/target/arm/usb-drv-arc.c | 186 ++++++++++----------- firmware/target/arm/usb-fw-pp502x.c | 49 +++++- firmware/target/arm/usb-target.h | 7 + firmware/usb.c | 65 +++++-- firmware/usbstack/usb_core.c | 6 +- firmware/usbstack/usb_storage.c | 2 +- 18 files changed, 276 insertions(+), 144 deletions(-) diff --git a/bootloader/gigabeat-s.c b/bootloader/gigabeat-s.c index e860a2e379..15cbcbed46 100644 --- a/bootloader/gigabeat-s.c +++ b/bootloader/gigabeat-s.c @@ -95,7 +95,6 @@ static void handle_usb(void) if (!usb_plugged() || !pause_if_button_pressed(true)) { /* Bang on the controller */ - usb_init_device(); return; } diff --git a/firmware/export/config-c200.h b/firmware/export/config-c200.h index d68d21455f..ff260dc956 100644 --- a/firmware/export/config-c200.h +++ b/firmware/export/config-c200.h @@ -180,6 +180,9 @@ /* enable these for the experimental usb stack */ #define HAVE_USBSTACK +#ifndef BOOTLOADER +#define USB_DETECT_BY_DRV +#endif #define USB_VENDOR_ID 0x0781 #define USB_PRODUCT_ID 0x7450 diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 2be64d95cc..7b27391c64 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h @@ -177,6 +177,9 @@ /* enable these for the experimental usb stack */ #define HAVE_USBSTACK +#ifndef BOOTLOADER +#define USB_DETECT_BY_DRV +#endif #define USB_VENDOR_ID 0x0781 #define USB_PRODUCT_ID 0x7421 diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h index 64f351c1ce..9e6029f00b 100644 --- a/firmware/export/config-gigabeat-s.h +++ b/firmware/export/config-gigabeat-s.h @@ -176,10 +176,12 @@ /* USB On-the-go */ #define CONFIG_USBOTG USBOTG_ARC -/* enable these for the experimental usb stack */ +/* enable these for the usb stack */ #define USE_ROCKBOX_USB #define HAVE_USBSTACK #define USB_STORAGE +/* usb stack and driver settings */ +#define USB_PORTSCX_PHY_TYPE PORTSCX_PTS_ULPI #define USB_VENDOR_ID 0x0930 #define USB_PRODUCT_ID 0x0010 @@ -201,7 +203,7 @@ /* Offset ( in the firmware file's header ) to the real data */ #define FIRMWARE_OFFSET_FILE_DATA 8 -#define HAVE_SERIAL +//#define HAVE_SERIAL #define HAVE_VOLUME_IN_LIST /*Remove Comments from UART_INT to enable the UART interrupts,*/ diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h index b572c788a9..b55a56b105 100755 --- a/firmware/export/imx31l.h +++ b/firmware/export/imx31l.h @@ -36,7 +36,11 @@ #define FRAME_SIZE (240*320*2) #define DEVBSS_ATTR __attribute__((section(".devbss"),nocommon)) -#define QHARRAY_ATTR __attribute__((section(".qharray"),nocommon)) +/* USBOTG */ +#define USB_QHARRAY_ATTR __attribute__((section(".qharray"),nocommon,aligned(2048))) +#define USB_NUM_ENDPOINTS 8 +#define USB_DEVBSS_ATTR DEVBSS_ATTR +#define USB_BASE OTG_BASE_ADDR /* * AIPS 1 @@ -1580,6 +1584,4 @@ #define UART_FIFO_CTRL 0x881 #define TIMEOUT 1000 -#define USB_BASE OTG_BASE_ADDR - #endif /* __IMX31L_H__ */ diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h index b4919a219e..0f622a907d 100644 --- a/firmware/export/pp5020.h +++ b/firmware/export/pp5020.h @@ -23,7 +23,12 @@ /* All info gleaned and/or copied from the iPodLinux project. */ -#define QHARRAY_ATTR __attribute__((section(".qharray"),nocommon)) +/* USBOTG */ +#define USB_NUM_ENDPOINTS 3 +/* This needs to be 2048 byte aligned, but USB_QHARRAY_ATTR should take care + * of that */ +#define USB_QHARRAY_ATTR __attribute__((section(".qharray"),nocommon,aligned(4))) +#define USB_DEVBSS_ATTR IBSS_ATTR /* DRAM starts at 0x10000000, but in Rockbox we remap it to 0x00000000 */ #define DRAM_START 0x10000000 diff --git a/firmware/export/usb.h b/firmware/export/usb.h index a6cfad5889..0a0539a622 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -33,8 +33,11 @@ enum { USB_INSERTED, /* Event+State */ USB_EXTRACTED, /* Event+State */ -#ifdef HAVE_USB_POWER - USB_POWERED, /* State */ +#if defined(HAVE_USB_POWER) || defined(USB_DETECT_BY_DRV) + USB_POWERED, /* Event+State */ +#endif +#ifdef USB_DETECT_BY_DRV + USB_UNPOWERED, /* Event */ #endif #ifdef HAVE_LCD_BITMAP USB_SCREENDUMP, /* State */ @@ -107,6 +110,7 @@ struct usb_transfer_completion_event_data void usb_init(void); void usb_enable(bool on); +void usb_attach(void); void usb_start_monitoring(void); void usb_close(void); void usb_acknowledge(long id); diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h index 7af8e43c8d..d0c8270d93 100644 --- a/firmware/export/usb_core.h +++ b/firmware/export/usb_core.h @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2007 by Björn Stenberg + * Copyright (C) 2007 by Björn Stenberg * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -35,14 +35,6 @@ /* endpoints */ #define EP_CONTROL 0 -#if CONFIG_CPU == IMX31L -#define NUM_ENDPOINTS 8 -#define USBDEVBSS_ATTR DEVBSS_ATTR -#else -#define USBDEVBSS_ATTR IBSS_ATTR -#define NUM_ENDPOINTS 3 -#endif - extern int usb_max_pkt_size; struct usb_class_driver; diff --git a/firmware/export/usb_drv.h b/firmware/export/usb_drv.h index 3d2e689050..23f6f4ce2a 100644 --- a/firmware/export/usb_drv.h +++ b/firmware/export/usb_drv.h @@ -24,9 +24,13 @@ #include "kernel.h" void usb_drv_startup(void); +void usb_drv_usb_detect_event(void); /* Target implemented */ +void usb_drv_int_enable(bool enable); /* Target implemented */ +void usb_drv_reset(void); void usb_drv_init(void); void usb_drv_exit(void); -void usb_drv_int(void); +void usb_drv_attach(void); +void usb_drv_int(void); /* Call from target INT handler */ void usb_drv_stall(int endpoint, bool stall,bool in); bool usb_drv_stalled(int endpoint,bool in); int usb_drv_send(int endpoint, void* ptr, int length); diff --git a/firmware/target/arm/imx31/gigabeat-s/system-target.h b/firmware/target/arm/imx31/gigabeat-s/system-target.h index 847e6cfc51..b99b31d1b4 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/system-target.h @@ -31,6 +31,14 @@ #define CPUFREQ_MAX CPU_FREQ #endif +/* For USB driver - no accuracy assurance */ +static inline void udelay(unsigned int usecs) +{ + unsigned int x; + for (x = 0; x < 300*usecs; x++) + asm volatile (""); +} + #if 0 static inline void udelay(unsigned int usecs) { diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c index cd8b513ecd..c0d7cb8d2a 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/usb-imx31.c @@ -29,6 +29,7 @@ #include "usb-target.h" #include "clkctl-imx31.h" #include "power-imx31.h" +#include "avic-imx31.h" #include "mc13783.h" static int usb_status = USB_EXTRACTED; @@ -75,11 +76,7 @@ bool usb_plugged(void) void usb_init_device(void) { - imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL); - - enable_transceiver(true); - - /* Module will be turned off later after firmware init */ + /* Do one-time inits */ usb_drv_startup(); /* Initially poll */ @@ -91,19 +88,37 @@ void usb_init_device(void) void usb_enable(bool on) { + /* Module clock should be on since since this could be called with + * OFF initially and writing module registers would hardlock otherwise. */ + imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL); + enable_transceiver(true); + if (on) { - imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL); - enable_transceiver(true); usb_core_init(); } else { - /* Module clock should be on since this could be called first */ - imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL); - enable_transceiver(true); usb_core_exit(); enable_transceiver(false); imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_OFF); } } + +void usb_attach(void) +{ + usb_enable(true); +} + +static void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void) +{ + usb_drv_int(); /* Call driver handler */ +} + +void usb_drv_int_enable(bool enable) +{ + if (enable) + avic_enable_int(USB_OTG, IRQ, 7, USB_OTG_HANDLER); + else + avic_disable_int(USB_OTG); +} diff --git a/firmware/target/arm/powermgmt-ascodec.c b/firmware/target/arm/powermgmt-ascodec.c index ab9fd7b490..6ee6209823 100644 --- a/firmware/target/arm/powermgmt-ascodec.c +++ b/firmware/target/arm/powermgmt-ascodec.c @@ -27,6 +27,8 @@ #include "adc.h" #include "powermgmt.h" #include "power.h" +#include "usb-target.h" +#include "usb.h" /*=========================================================================== * These parameters may be defined per target: @@ -132,6 +134,10 @@ static inline void charger_plugged(void) { batt_threshold = BATT_FULL_VOLTAGE; /* Start with topped value. */ battery_voltage_sync(); +#if defined(USB_STATUS_BY_EVENT) && defined(USB_DETECT_BY_DRV) + /* Charger pin detect is USB pin detect */ + usb_connect_event(true); +#endif } static inline void charger_control(void) @@ -186,6 +192,10 @@ static inline void charger_unplugged(void) disable_charger(); if (charge_state >= CHARGE_STATE_ERROR) charge_state = DISCHARGING; /* Reset error */ +#if defined(USB_STATUS_BY_EVENT) && defined(USB_DETECT_BY_DRV) + /* Charger pin detect is USB pin detect */ + usb_connect_event(false); +#endif } /* Main charging algorithm - called from powermgmt.c */ diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c index 1cdc0f9e90..99845c2a49 100644 --- a/firmware/target/arm/usb-drv-arc.c +++ b/firmware/target/arm/usb-drv-arc.c @@ -9,7 +9,7 @@ * * Driver for ARC USBOTG Device Controller * - * Copyright (C) 2007 by Björn Stenberg + * Copyright (C) 2007 by Björn Stenberg * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,11 +33,6 @@ //#define LOGF_ENABLE #include "logf.h" -#if CONFIG_CPU == IMX31L -#include "avic-imx31.h" -static void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void); -#endif - /* USB device mode registers (Little Endian) */ #define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000)) @@ -326,8 +321,8 @@ struct transfer_descriptor { unsigned int reserved; } __attribute__ ((packed)); -static struct transfer_descriptor td_array[NUM_ENDPOINTS*2] - USBDEVBSS_ATTR __attribute__((aligned(32))); +static struct transfer_descriptor td_array[USB_NUM_ENDPOINTS*2] + USB_DEVBSS_ATTR __attribute__((aligned(32))); /* manual: 32.13.1 Endpoint Queue Head (dQH) */ struct queue_head { @@ -342,17 +337,10 @@ struct queue_head { unsigned int wait; /* for softwate use, indicates if the transfer is blocking */ } __attribute__((packed)); -#if CONFIG_CPU == IMX31L -static struct queue_head qh_array[NUM_ENDPOINTS*2] - QHARRAY_ATTR __attribute__((aligned (2048))); -#else -/* This still needs to be 2048 byte aligned, but QHARRAY_ATTR should take - care of that */ -static struct queue_head qh_array[NUM_ENDPOINTS*2] - QHARRAY_ATTR __attribute__((aligned (4))); -#endif +static struct queue_head qh_array[USB_NUM_ENDPOINTS*2] + USB_QHARRAY_ATTR; -static struct wakeup transfer_completion_signal[NUM_ENDPOINTS*2] +static struct wakeup transfer_completion_signal[USB_NUM_ENDPOINTS*2] SHAREDBSS_ATTR; static const unsigned int pipe2mask[] = { @@ -363,7 +351,7 @@ static const unsigned int pipe2mask[] = { 0x10, 0x100000, }; -static char ep_allocation[NUM_ENDPOINTS]; +static char ep_allocation[USB_NUM_ENDPOINTS]; /*-------------------------------------------------------------------------*/ static void transfer_completed(void); @@ -378,52 +366,46 @@ static void init_control_queue_heads(void); static void init_bulk_queue_heads(void); static void init_endpoints(void); /*-------------------------------------------------------------------------*/ - -bool usb_drv_powered(void) +static void usb_drv_stop(void) { - return (REG_OTGSC & OTGSC_B_SESSION_VALID) ? true : false; + /* disable interrupts */ + REG_USBINTR = 0; + /* stop usb controller (disconnect) */ + REG_USBCMD &= ~USBCMD_RUN; } -/* One-time driver startup init */ -void usb_drv_startup(void) +void usb_drv_reset(void) { -#if CONFIG_CPU == IMX31L && defined(BOOTLOADER) - /* This is the bootloader - activate the OTG controller or cold - * connect later could/will fail */ + int oldlevel = disable_irq_save(); REG_USBCMD &= ~USBCMD_RUN; + restore_irq(oldlevel); +#ifdef USB_PORTSCX_PHY_TYPE + /* If a PHY type is specified, set it now */ + REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | USB_PORTSCX_PHY_TYPE; +#endif sleep(HZ/20); REG_USBCMD |= USBCMD_CTRL_RESET; while (REG_USBCMD & USBCMD_CTRL_RESET); +} - /* Set to ULPI */ - REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_ULPI; - sleep(HZ/10); -#endif - +/* One-time driver startup init */ +void usb_drv_startup(void) +{ /* Initialize all the signal objects once */ int i; - for(i=0;i