linux-omap-* 2.6.29: add l1 cache performance tweak from l-a-k ml
authorKoen Kooi <koen@openembedded.org>
Wed, 2 Sep 2009 20:13:29 +0000 (22:13 +0200)
committerKoen Kooi <koen@openembedded.org>
Wed, 2 Sep 2009 20:14:08 +0000 (22:14 +0200)
* also sync patch between pm and regular kernels

37 files changed:
conf/machine/include/omap3.inc
recipes/linux/linux-omap-2.6.29/cache/copy-page-tweak.patch [new file with mode: 0644]
recipes/linux/linux-omap-2.6.29/cache/l1cache-shift.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/beagleboard/defconfig
recipes/linux/linux-omap-pm-2.6.29/cache/copy-page-tweak.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/cache/l1cache-shift.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0002-USB-composite-avoid-inconsistent-lock-state.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0012-musb-fix-possible-panic-while-resuming.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0017-musb_host-refactor-URB-giveback.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0018-musb-split-out-CPPI-interrupt-handler.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0019-musb_host-simplify-check-for-active-URB.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0023-musb-add-high-bandwidth-ISO-support.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0024-USB-otg-adding-nop-usb-transceiver.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0027-musb-otg-timer-cleanup.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch [new file with mode: 0644]
recipes/linux/linux-omap-pm_2.6.29.bb
recipes/linux/linux-omap_2.6.29.bb

index 163c9c9..889e0f6 100644 (file)
@@ -1,7 +1,7 @@
 require conf/machine/include/tune-cortexa8.inc
 PREFERRED_PROVIDER_virtual/kernel = "linux-omap"
 # Increase this everytime you change something in the kernel
-MACHINE_KERNEL_PR = "r43
+MACHINE_KERNEL_PR = "r44
 
 KERNEL_IMAGETYPE = "uImage"
 
diff --git a/recipes/linux/linux-omap-2.6.29/cache/copy-page-tweak.patch b/recipes/linux/linux-omap-2.6.29/cache/copy-page-tweak.patch
new file mode 100644 (file)
index 0000000..9da3740
--- /dev/null
@@ -0,0 +1,169 @@
+Path: news.gmane.org!not-for-mail
+From: "Kirill A. Shutemov" <kirill@shutemov.name>
+Newsgroups: gmane.linux.ports.arm.kernel
+Subject: [PATCH] ARM: copy_page.S: take into account the size of the cache line
+Date: Wed,  2 Sep 2009 20:19:58 +0300
+Lines: 92
+Approved: news@gmane.org
+Message-ID: <1251911998-3112-1-git-send-email-kirill__11898.5180197798$1251901300$gmane$org@shutemov.name>
+References: <20090902132423.GA12595@n2100.arm.linux.org.uk>
+NNTP-Posting-Host: lo.gmane.org
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+X-Trace: ger.gmane.org 1251901300 3930 80.91.229.12 (2 Sep 2009 14:21:40 GMT)
+X-Complaints-To: usenet@ger.gmane.org
+NNTP-Posting-Date: Wed, 2 Sep 2009 14:21:40 +0000 (UTC)
+Cc: Bityutskiy Artem <Artem.Bityutskiy@nokia.com>,
+       "Kirill A. Shutemov" <kirill@shutemov.name>,
+       Siarhei Siamashka <siarhei.siamashka@nokia.com>,
+       Moiseichuk Leonid <leonid.moiseichuk@nokia.com>,
+       Koskinen Aaro <aaro.koskinen@nokia.com>
+To: linux-arm-kernel@lists.infradead.org,
+       linux-kernel@vger.kernel.org
+Original-X-From: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org Wed Sep 02 16:21:32 2009
+Return-path: <linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org>
+Envelope-to: linux-arm-kernel@m.gmane.org
+Original-Received: from bombadil.infradead.org ([18.85.46.34])
+       by lo.gmane.org with esmtp (Exim 4.50)
+       id 1MiqiI-0003K3-An
+       for linux-arm-kernel@m.gmane.org; Wed, 02 Sep 2009 16:21:30 +0200
+Original-Received: from localhost ([::1] helo=bombadil.infradead.org)
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1MiqhG-0005iZ-OK; Wed, 02 Sep 2009 14:20:26 +0000
+Original-Received: from mail-bw0-f222.google.com ([209.85.218.222])
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1Miqh8-0005LP-ED for linux-arm-kernel@lists.infradead.org;
+       Wed, 02 Sep 2009 14:20:23 +0000
+Original-Received: by bwz22 with SMTP id 22so788877bwz.18
+       for <linux-arm-kernel@lists.infradead.org>;
+       Wed, 02 Sep 2009 07:20:06 -0700 (PDT)
+Original-Received: by 10.204.162.143 with SMTP id v15mr6724283bkx.50.1251901206540;
+       Wed, 02 Sep 2009 07:20:06 -0700 (PDT)
+Original-Received: from localhost.localdomain (viktor.cosmicparrot.net [217.152.255.14])
+       by mx.google.com with ESMTPS id d13sm11540576fka.2.2009.09.02.07.20.05
+       (version=SSLv3 cipher=RC4-MD5); Wed, 02 Sep 2009 07:20:05 -0700 (PDT)
+X-Mailer: git-send-email 1.6.4.2
+In-Reply-To: <20090902132423.GA12595@n2100.arm.linux.org.uk>
+X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.5 (LGPL) )
+       MR-646709E3 
+X-CRM114-CacheID: sfid-20090902_102018_607316_8AE98A04 
+X-CRM114-Status: UNSURE (   9.59  )
+X-CRM114-Notice: Please train this message.
+X-Spam-Score: -4.2 (----)
+X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary:
+       Content analysis details:   (-4.2 points)
+       pts rule name              description
+       ---- ----------------------
+       --------------------------------------------------
+       -2.6 BAYES_00 BODY: Bayesian spam probability is 0 to 1%
+       [score: 0.0000]
+       -1.6 AWL AWL: From: address is in the auto white-list
+X-BeenThere: linux-arm-kernel@lists.infradead.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: <linux-arm-kernel.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
+List-Post: <mailto:linux-arm-kernel@lists.infradead.org>
+List-Help: <mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>
+Original-Sender: linux-arm-kernel-bounces@lists.infradead.org
+Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org
+Xref: news.gmane.org gmane.linux.ports.arm.kernel:65025
+Archived-At: <http://permalink.gmane.org/gmane.linux.ports.arm.kernel/65025>
+
+Optimized version of copy_page() was written with assumption that cache
+line size is 32 bytes. On Cortex-A8 cache line size is 64 bytes.
+
+This patch tries to generalize copy_page() to work with any cache line
+size if cache line size is multiple of 16 and page size is multiple of
+two cache line size.
+
+After this optimization we've got ~25% speedup on OMAP3(tested in
+userspace).
+
+There is test for kernelspace which trigger copy-on-write after fork():
+
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+
+ #define BUF_SIZE (10000*4096)
+ #define NFORK 200
+
+ int main(int argc, char **argv)
+ {
+         char *buf = malloc(BUF_SIZE);
+         int i;
+
+         memset(buf, 0, BUF_SIZE);
+
+         for(i = 0; i < NFORK; i++) {
+                 if (fork()) {
+                         wait(NULL);
+                 } else {
+                         int j;
+
+                         for(j = 0; j < BUF_SIZE; j+= 4096)
+                                 buf[j] = (j & 0xFF) + 1;
+                         break;
+                 }
+         }
+
+         free(buf);
+         return 0;
+ }
+
+Before optimization this test takes ~66 seconds, after optimization
+takes ~56 seconds.
+
+Signed-off-by: Siarhei Siamashka <siarhei.siamashka@nokia.com>
+Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
+---
+ arch/arm/lib/copy_page.S |   16 ++++++++--------
+ 1 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S
+index 6ae04db..6ee2f67 100644
+--- a/arch/arm/lib/copy_page.S
++++ b/arch/arm/lib/copy_page.S
+@@ -12,8 +12,9 @@
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+ #include <asm/asm-offsets.h>
++#include <asm/cache.h>
+-#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
++#define COPY_COUNT (PAGE_SZ / (2 * L1_CACHE_BYTES) PLD( -1 ))
+               .text
+               .align  5
+@@ -26,17 +27,16 @@
+ ENTRY(copy_page)
+               stmfd   sp!, {r4, lr}                   @       2
+       PLD(    pld     [r1, #0]                )
+-      PLD(    pld     [r1, #32]               )
++      PLD(    pld     [r1, #L1_CACHE_BYTES]           )
+               mov     r2, #COPY_COUNT                 @       1
+               ldmia   r1!, {r3, r4, ip, lr}           @       4+1
+-1:    PLD(    pld     [r1, #64]               )
+-      PLD(    pld     [r1, #96]               )
+-2:            stmia   r0!, {r3, r4, ip, lr}           @       4
+-              ldmia   r1!, {r3, r4, ip, lr}           @       4+1
+-              stmia   r0!, {r3, r4, ip, lr}           @       4
+-              ldmia   r1!, {r3, r4, ip, lr}           @       4+1
++1:    PLD(    pld     [r1, #2 * L1_CACHE_BYTES])
++      PLD(    pld     [r1, #3 * L1_CACHE_BYTES])
++2:
++      .rept   (2 * L1_CACHE_BYTES / 16 - 1)
+               stmia   r0!, {r3, r4, ip, lr}           @       4
+               ldmia   r1!, {r3, r4, ip, lr}           @       4
++      .endr
+               subs    r2, r2, #1                      @       1
+               stmia   r0!, {r3, r4, ip, lr}           @       4
+               ldmgtia r1!, {r3, r4, ip, lr}           @       4
+-- 
+1.6.4.2
diff --git a/recipes/linux/linux-omap-2.6.29/cache/l1cache-shift.patch b/recipes/linux/linux-omap-2.6.29/cache/l1cache-shift.patch
new file mode 100644 (file)
index 0000000..e58d49c
--- /dev/null
@@ -0,0 +1,115 @@
+Path: news.gmane.org!not-for-mail
+From: "Kirill A. Shutemov" <kirill@shutemov.name>
+Newsgroups: gmane.linux.ports.arm.kernel
+Subject: [PATCH 1/2] ARM: Introduce ARM_L1_CACHE_SHIFT to define cache line
+       size
+Date: Wed,  2 Sep 2009 19:11:52 +0300
+Lines: 39
+Approved: news@gmane.org
+Message-ID: <1251907913-16261-1-git-send-email-kirill__21953.4654439942$1251897245$gmane$org@shutemov.name>
+NNTP-Posting-Host: lo.gmane.org
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+X-Trace: ger.gmane.org 1251897245 21910 80.91.229.12 (2 Sep 2009 13:14:05 GMT)
+X-Complaints-To: usenet@ger.gmane.org
+NNTP-Posting-Date: Wed, 2 Sep 2009 13:14:05 +0000 (UTC)
+Cc: Bityutskiy Artem <Artem.Bityutskiy@nokia.com>,
+       "Kirill A. Shutemov" <kirill@shutemov.name>,
+       Siarhei Siamashka <siarhei.siamashka@nokia.com>,
+       Moiseichuk Leonid <leonid.moiseichuk@nokia.com>,
+       Koskinen Aaro <aaro.koskinen@nokia.com>
+To: linux-arm-kernel@lists.infradead.org,
+       linux-kernel@vger.kernel.org
+Original-X-From: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org Wed Sep 02 15:13:57 2009
+Return-path: <linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org>
+Envelope-to: linux-arm-kernel@m.gmane.org
+Original-Received: from bombadil.infradead.org ([18.85.46.34])
+       by lo.gmane.org with esmtp (Exim 4.50)
+       id 1Mipeu-0000ZH-G2
+       for linux-arm-kernel@m.gmane.org; Wed, 02 Sep 2009 15:13:56 +0200
+Original-Received: from localhost ([::1] helo=bombadil.infradead.org)
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1MipdW-00035E-AP; Wed, 02 Sep 2009 13:12:30 +0000
+Original-Received: from mail-bw0-f222.google.com ([209.85.218.222])
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1Mipd1-00031v-Ga for linux-arm-kernel@lists.infradead.org;
+       Wed, 02 Sep 2009 13:12:04 +0000
+Original-Received: by bwz22 with SMTP id 22so735896bwz.18
+       for <linux-arm-kernel@lists.infradead.org>;
+       Wed, 02 Sep 2009 06:11:56 -0700 (PDT)
+Original-Received: by 10.204.34.199 with SMTP id m7mr6687295bkd.48.1251897116013;
+       Wed, 02 Sep 2009 06:11:56 -0700 (PDT)
+Original-Received: from localhost.localdomain (viktor.cosmicparrot.net [217.152.255.14])
+       by mx.google.com with ESMTPS id c28sm2027077fka.19.2009.09.02.06.11.54
+       (version=SSLv3 cipher=RC4-MD5); Wed, 02 Sep 2009 06:11:55 -0700 (PDT)
+X-Mailer: git-send-email 1.6.3.4
+X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.5 (LGPL) )
+       MR-646709E3 
+X-CRM114-CacheID: sfid-20090902_091159_726883_CEFBECD2 
+X-CRM114-Status: UNSURE (   8.83  )
+X-CRM114-Notice: Please train this message.
+X-Spam-Score: -4.6 (----)
+X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary:
+       Content analysis details:   (-4.6 points)
+       pts rule name              description
+       ---- ----------------------
+       --------------------------------------------------
+       -2.6 BAYES_00 BODY: Bayesian spam probability is 0 to 1%
+       [score: 0.0000]
+       -2.0 AWL AWL: From: address is in the auto white-list
+X-BeenThere: linux-arm-kernel@lists.infradead.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: <linux-arm-kernel.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
+List-Post: <mailto:linux-arm-kernel@lists.infradead.org>
+List-Help: <mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>
+Original-Sender: linux-arm-kernel-bounces@lists.infradead.org
+Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org
+Xref: news.gmane.org gmane.linux.ports.arm.kernel:65017
+Archived-At: <http://permalink.gmane.org/gmane.linux.ports.arm.kernel/65017>
+
+Currently kernel believes that all ARM CPUs have L1_CACHE_SHIFT == 5.
+It's not true at least for CPUs based on Cortex-A8.
+
+List of CPUs with cache line size != 32 should be expanded later.
+
+Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
+---
+ arch/arm/include/asm/cache.h |    2 +-
+ arch/arm/mm/Kconfig          |    5 +++++
+ 2 files changed, 6 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
+index feaa75f..2ee7743 100644
+--- a/arch/arm/include/asm/cache.h
++++ b/arch/arm/include/asm/cache.h
+@@ -4,7 +4,7 @@
+ #ifndef __ASMARM_CACHE_H
+ #define __ASMARM_CACHE_H
+-#define L1_CACHE_SHIFT                5
++#define L1_CACHE_SHIFT                (CONFIG_ARM_L1_CACHE_SHIFT)
+ #define L1_CACHE_BYTES                (1 << L1_CACHE_SHIFT)
+ /*
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index 83c025e..3c37d4c 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -771,3 +771,8 @@ config CACHE_XSC3L2
+       select OUTER_CACHE
+       help
+         This option enables the L2 cache on XScale3.
++
++config ARM_L1_CACHE_SHIFT
++      int
++      default 6 if ARCH_OMAP3
++      default 5
+-- 
+1.6.3.4
index ca5adf2..9cb8ab5 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.29-omap1
-# Mon Aug 17 17:49:14 2009
+# Wed Sep  2 21:59:02 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -199,7 +199,7 @@ CONFIG_OMAP_BOOT_REASON=y
 # CONFIG_OMAP_MUX is not set
 CONFIG_OMAP_MCBSP=y
 # CONFIG_OMAP_MBOX_FWK is not set
-# CONFIG_OMAP_IOMMU is not set
+CONFIG_OMAP_IOMMU=m
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 # CONFIG_OMAP3_DEBOBS is not set
@@ -253,6 +253,7 @@ CONFIG_ARM_THUMBEE=y
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
 # CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
 
 #
 # Bus support
@@ -1514,6 +1515,7 @@ CONFIG_MEDIA_TUNER_MXL5005S=m
 CONFIG_VIDEO_V4L2=m
 CONFIG_VIDEO_V4L1=m
 CONFIG_VIDEOBUF_GEN=m
+CONFIG_VIDEOBUF_DMA_SG=m
 CONFIG_VIDEOBUF_VMALLOC=m
 CONFIG_VIDEOBUF_DVB=m
 CONFIG_VIDEO_IR=m
@@ -1537,8 +1539,8 @@ CONFIG_VIDEO_VIVI=m
 # CONFIG_VIDEO_SAA5246A is not set
 # CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_VIDEO_AU0828 is not set
-# CONFIG_VIDEO_OMAP3 is not set
-# CONFIG_VIDEO_OMAP34XX_ISP_RESIZER is not set
+CONFIG_VIDEO_OMAP3=m
+CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=m
 # CONFIG_SOC_CAMERA is not set
 CONFIG_V4L_USB_DRIVERS=y
 CONFIG_USB_VIDEO_CLASS=m
@@ -2136,6 +2138,7 @@ CONFIG_USB_OTG_UTILS=y
 CONFIG_USB_GPIO_VBUS=y
 # CONFIG_ISP1301_OMAP is not set
 CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/recipes/linux/linux-omap-pm-2.6.29/cache/copy-page-tweak.patch b/recipes/linux/linux-omap-pm-2.6.29/cache/copy-page-tweak.patch
new file mode 100644 (file)
index 0000000..9da3740
--- /dev/null
@@ -0,0 +1,169 @@
+Path: news.gmane.org!not-for-mail
+From: "Kirill A. Shutemov" <kirill@shutemov.name>
+Newsgroups: gmane.linux.ports.arm.kernel
+Subject: [PATCH] ARM: copy_page.S: take into account the size of the cache line
+Date: Wed,  2 Sep 2009 20:19:58 +0300
+Lines: 92
+Approved: news@gmane.org
+Message-ID: <1251911998-3112-1-git-send-email-kirill__11898.5180197798$1251901300$gmane$org@shutemov.name>
+References: <20090902132423.GA12595@n2100.arm.linux.org.uk>
+NNTP-Posting-Host: lo.gmane.org
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+X-Trace: ger.gmane.org 1251901300 3930 80.91.229.12 (2 Sep 2009 14:21:40 GMT)
+X-Complaints-To: usenet@ger.gmane.org
+NNTP-Posting-Date: Wed, 2 Sep 2009 14:21:40 +0000 (UTC)
+Cc: Bityutskiy Artem <Artem.Bityutskiy@nokia.com>,
+       "Kirill A. Shutemov" <kirill@shutemov.name>,
+       Siarhei Siamashka <siarhei.siamashka@nokia.com>,
+       Moiseichuk Leonid <leonid.moiseichuk@nokia.com>,
+       Koskinen Aaro <aaro.koskinen@nokia.com>
+To: linux-arm-kernel@lists.infradead.org,
+       linux-kernel@vger.kernel.org
+Original-X-From: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org Wed Sep 02 16:21:32 2009
+Return-path: <linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org>
+Envelope-to: linux-arm-kernel@m.gmane.org
+Original-Received: from bombadil.infradead.org ([18.85.46.34])
+       by lo.gmane.org with esmtp (Exim 4.50)
+       id 1MiqiI-0003K3-An
+       for linux-arm-kernel@m.gmane.org; Wed, 02 Sep 2009 16:21:30 +0200
+Original-Received: from localhost ([::1] helo=bombadil.infradead.org)
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1MiqhG-0005iZ-OK; Wed, 02 Sep 2009 14:20:26 +0000
+Original-Received: from mail-bw0-f222.google.com ([209.85.218.222])
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1Miqh8-0005LP-ED for linux-arm-kernel@lists.infradead.org;
+       Wed, 02 Sep 2009 14:20:23 +0000
+Original-Received: by bwz22 with SMTP id 22so788877bwz.18
+       for <linux-arm-kernel@lists.infradead.org>;
+       Wed, 02 Sep 2009 07:20:06 -0700 (PDT)
+Original-Received: by 10.204.162.143 with SMTP id v15mr6724283bkx.50.1251901206540;
+       Wed, 02 Sep 2009 07:20:06 -0700 (PDT)
+Original-Received: from localhost.localdomain (viktor.cosmicparrot.net [217.152.255.14])
+       by mx.google.com with ESMTPS id d13sm11540576fka.2.2009.09.02.07.20.05
+       (version=SSLv3 cipher=RC4-MD5); Wed, 02 Sep 2009 07:20:05 -0700 (PDT)
+X-Mailer: git-send-email 1.6.4.2
+In-Reply-To: <20090902132423.GA12595@n2100.arm.linux.org.uk>
+X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.5 (LGPL) )
+       MR-646709E3 
+X-CRM114-CacheID: sfid-20090902_102018_607316_8AE98A04 
+X-CRM114-Status: UNSURE (   9.59  )
+X-CRM114-Notice: Please train this message.
+X-Spam-Score: -4.2 (----)
+X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary:
+       Content analysis details:   (-4.2 points)
+       pts rule name              description
+       ---- ----------------------
+       --------------------------------------------------
+       -2.6 BAYES_00 BODY: Bayesian spam probability is 0 to 1%
+       [score: 0.0000]
+       -1.6 AWL AWL: From: address is in the auto white-list
+X-BeenThere: linux-arm-kernel@lists.infradead.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: <linux-arm-kernel.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
+List-Post: <mailto:linux-arm-kernel@lists.infradead.org>
+List-Help: <mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>
+Original-Sender: linux-arm-kernel-bounces@lists.infradead.org
+Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org
+Xref: news.gmane.org gmane.linux.ports.arm.kernel:65025
+Archived-At: <http://permalink.gmane.org/gmane.linux.ports.arm.kernel/65025>
+
+Optimized version of copy_page() was written with assumption that cache
+line size is 32 bytes. On Cortex-A8 cache line size is 64 bytes.
+
+This patch tries to generalize copy_page() to work with any cache line
+size if cache line size is multiple of 16 and page size is multiple of
+two cache line size.
+
+After this optimization we've got ~25% speedup on OMAP3(tested in
+userspace).
+
+There is test for kernelspace which trigger copy-on-write after fork():
+
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+
+ #define BUF_SIZE (10000*4096)
+ #define NFORK 200
+
+ int main(int argc, char **argv)
+ {
+         char *buf = malloc(BUF_SIZE);
+         int i;
+
+         memset(buf, 0, BUF_SIZE);
+
+         for(i = 0; i < NFORK; i++) {
+                 if (fork()) {
+                         wait(NULL);
+                 } else {
+                         int j;
+
+                         for(j = 0; j < BUF_SIZE; j+= 4096)
+                                 buf[j] = (j & 0xFF) + 1;
+                         break;
+                 }
+         }
+
+         free(buf);
+         return 0;
+ }
+
+Before optimization this test takes ~66 seconds, after optimization
+takes ~56 seconds.
+
+Signed-off-by: Siarhei Siamashka <siarhei.siamashka@nokia.com>
+Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
+---
+ arch/arm/lib/copy_page.S |   16 ++++++++--------
+ 1 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S
+index 6ae04db..6ee2f67 100644
+--- a/arch/arm/lib/copy_page.S
++++ b/arch/arm/lib/copy_page.S
+@@ -12,8 +12,9 @@
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+ #include <asm/asm-offsets.h>
++#include <asm/cache.h>
+-#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
++#define COPY_COUNT (PAGE_SZ / (2 * L1_CACHE_BYTES) PLD( -1 ))
+               .text
+               .align  5
+@@ -26,17 +27,16 @@
+ ENTRY(copy_page)
+               stmfd   sp!, {r4, lr}                   @       2
+       PLD(    pld     [r1, #0]                )
+-      PLD(    pld     [r1, #32]               )
++      PLD(    pld     [r1, #L1_CACHE_BYTES]           )
+               mov     r2, #COPY_COUNT                 @       1
+               ldmia   r1!, {r3, r4, ip, lr}           @       4+1
+-1:    PLD(    pld     [r1, #64]               )
+-      PLD(    pld     [r1, #96]               )
+-2:            stmia   r0!, {r3, r4, ip, lr}           @       4
+-              ldmia   r1!, {r3, r4, ip, lr}           @       4+1
+-              stmia   r0!, {r3, r4, ip, lr}           @       4
+-              ldmia   r1!, {r3, r4, ip, lr}           @       4+1
++1:    PLD(    pld     [r1, #2 * L1_CACHE_BYTES])
++      PLD(    pld     [r1, #3 * L1_CACHE_BYTES])
++2:
++      .rept   (2 * L1_CACHE_BYTES / 16 - 1)
+               stmia   r0!, {r3, r4, ip, lr}           @       4
+               ldmia   r1!, {r3, r4, ip, lr}           @       4
++      .endr
+               subs    r2, r2, #1                      @       1
+               stmia   r0!, {r3, r4, ip, lr}           @       4
+               ldmgtia r1!, {r3, r4, ip, lr}           @       4
+-- 
+1.6.4.2
diff --git a/recipes/linux/linux-omap-pm-2.6.29/cache/l1cache-shift.patch b/recipes/linux/linux-omap-pm-2.6.29/cache/l1cache-shift.patch
new file mode 100644 (file)
index 0000000..e58d49c
--- /dev/null
@@ -0,0 +1,115 @@
+Path: news.gmane.org!not-for-mail
+From: "Kirill A. Shutemov" <kirill@shutemov.name>
+Newsgroups: gmane.linux.ports.arm.kernel
+Subject: [PATCH 1/2] ARM: Introduce ARM_L1_CACHE_SHIFT to define cache line
+       size
+Date: Wed,  2 Sep 2009 19:11:52 +0300
+Lines: 39
+Approved: news@gmane.org
+Message-ID: <1251907913-16261-1-git-send-email-kirill__21953.4654439942$1251897245$gmane$org@shutemov.name>
+NNTP-Posting-Host: lo.gmane.org
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+X-Trace: ger.gmane.org 1251897245 21910 80.91.229.12 (2 Sep 2009 13:14:05 GMT)
+X-Complaints-To: usenet@ger.gmane.org
+NNTP-Posting-Date: Wed, 2 Sep 2009 13:14:05 +0000 (UTC)
+Cc: Bityutskiy Artem <Artem.Bityutskiy@nokia.com>,
+       "Kirill A. Shutemov" <kirill@shutemov.name>,
+       Siarhei Siamashka <siarhei.siamashka@nokia.com>,
+       Moiseichuk Leonid <leonid.moiseichuk@nokia.com>,
+       Koskinen Aaro <aaro.koskinen@nokia.com>
+To: linux-arm-kernel@lists.infradead.org,
+       linux-kernel@vger.kernel.org
+Original-X-From: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org Wed Sep 02 15:13:57 2009
+Return-path: <linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org>
+Envelope-to: linux-arm-kernel@m.gmane.org
+Original-Received: from bombadil.infradead.org ([18.85.46.34])
+       by lo.gmane.org with esmtp (Exim 4.50)
+       id 1Mipeu-0000ZH-G2
+       for linux-arm-kernel@m.gmane.org; Wed, 02 Sep 2009 15:13:56 +0200
+Original-Received: from localhost ([::1] helo=bombadil.infradead.org)
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1MipdW-00035E-AP; Wed, 02 Sep 2009 13:12:30 +0000
+Original-Received: from mail-bw0-f222.google.com ([209.85.218.222])
+       by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))
+       id 1Mipd1-00031v-Ga for linux-arm-kernel@lists.infradead.org;
+       Wed, 02 Sep 2009 13:12:04 +0000
+Original-Received: by bwz22 with SMTP id 22so735896bwz.18
+       for <linux-arm-kernel@lists.infradead.org>;
+       Wed, 02 Sep 2009 06:11:56 -0700 (PDT)
+Original-Received: by 10.204.34.199 with SMTP id m7mr6687295bkd.48.1251897116013;
+       Wed, 02 Sep 2009 06:11:56 -0700 (PDT)
+Original-Received: from localhost.localdomain (viktor.cosmicparrot.net [217.152.255.14])
+       by mx.google.com with ESMTPS id c28sm2027077fka.19.2009.09.02.06.11.54
+       (version=SSLv3 cipher=RC4-MD5); Wed, 02 Sep 2009 06:11:55 -0700 (PDT)
+X-Mailer: git-send-email 1.6.3.4
+X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.5 (LGPL) )
+       MR-646709E3 
+X-CRM114-CacheID: sfid-20090902_091159_726883_CEFBECD2 
+X-CRM114-Status: UNSURE (   8.83  )
+X-CRM114-Notice: Please train this message.
+X-Spam-Score: -4.6 (----)
+X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary:
+       Content analysis details:   (-4.6 points)
+       pts rule name              description
+       ---- ----------------------
+       --------------------------------------------------
+       -2.6 BAYES_00 BODY: Bayesian spam probability is 0 to 1%
+       [score: 0.0000]
+       -2.0 AWL AWL: From: address is in the auto white-list
+X-BeenThere: linux-arm-kernel@lists.infradead.org
+X-Mailman-Version: 2.1.12
+Precedence: list
+List-Id: <linux-arm-kernel.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
+List-Post: <mailto:linux-arm-kernel@lists.infradead.org>
+List-Help: <mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>, 
+       <mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>
+Original-Sender: linux-arm-kernel-bounces@lists.infradead.org
+Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org
+Xref: news.gmane.org gmane.linux.ports.arm.kernel:65017
+Archived-At: <http://permalink.gmane.org/gmane.linux.ports.arm.kernel/65017>
+
+Currently kernel believes that all ARM CPUs have L1_CACHE_SHIFT == 5.
+It's not true at least for CPUs based on Cortex-A8.
+
+List of CPUs with cache line size != 32 should be expanded later.
+
+Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
+---
+ arch/arm/include/asm/cache.h |    2 +-
+ arch/arm/mm/Kconfig          |    5 +++++
+ 2 files changed, 6 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
+index feaa75f..2ee7743 100644
+--- a/arch/arm/include/asm/cache.h
++++ b/arch/arm/include/asm/cache.h
+@@ -4,7 +4,7 @@
+ #ifndef __ASMARM_CACHE_H
+ #define __ASMARM_CACHE_H
+-#define L1_CACHE_SHIFT                5
++#define L1_CACHE_SHIFT                (CONFIG_ARM_L1_CACHE_SHIFT)
+ #define L1_CACHE_BYTES                (1 << L1_CACHE_SHIFT)
+ /*
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index 83c025e..3c37d4c 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -771,3 +771,8 @@ config CACHE_XSC3L2
+       select OUTER_CACHE
+       help
+         This option enables the L2 cache on XScale3.
++
++config ARM_L1_CACHE_SHIFT
++      int
++      default 6 if ARCH_OMAP3
++      default 5
+-- 
+1.6.3.4
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch
new file mode 100644 (file)
index 0000000..a7898d1
--- /dev/null
@@ -0,0 +1,43 @@
+From a9199e8ab6d6fb105aa251d6bf2192e7eafac8ee Mon Sep 17 00:00:00 2001
+From: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
+Date: Tue, 24 Mar 2009 17:22:53 -0700
+Subject: [PATCH] USB: musb: only turn off vbus in OTG hosts
+
+Except on DaVinci, VBUS is now switched off as part of idling the
+USB link (after a_wait_bcon) whenever a device is disconnected
+from host.  This is correct for OTG hosts, where either SRP or
+an ID interrupt could turn VBUS on again.
+
+However, for non-OTG hosts there's no way to turn VBUS on again,
+so the host becomes unusable.  And the procfs entry which once
+allowed a manual workaround for this is now gone.
+
+This patch adds an is_otg_enabled() check before scheduling the
+switch-off timer in disconnect path, supporting a "classic host"
+mode where SRP is unavailable.
+
+[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: tweak patch description ]
+
+Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
+---
+ drivers/usb/musb/musb_core.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index af77e46..338cd16 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -769,7 +769,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+               case OTG_STATE_A_SUSPEND:
+                       usb_hcd_resume_root_hub(musb_to_hcd(musb));
+                       musb_root_disconnect(musb);
+-                      if (musb->a_wait_bcon != 0)
++                      if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
+                               musb_platform_try_idle(musb, jiffies
+                                       + msecs_to_jiffies(musb->a_wait_bcon));
+                       break;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0002-USB-composite-avoid-inconsistent-lock-state.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0002-USB-composite-avoid-inconsistent-lock-state.patch
new file mode 100644 (file)
index 0000000..5cb7bcb
--- /dev/null
@@ -0,0 +1,76 @@
+From 83eb44b1c84f99d9a5c67612bd94b4ed7c43f64c Mon Sep 17 00:00:00 2001
+From: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+Date: Tue, 24 Mar 2009 17:22:49 -0700
+Subject: [PATCH] USB: composite: avoid inconsistent lock state
+
+Avoid the following INFO from lock debugging:
+
+[  369.126112] =================================
+[  369.132063] [ INFO: inconsistent lock state ]
+[  369.136457] 2.6.28-maemo1 #1
+[  369.139387] ---------------------------------
+[  369.143782] inconsistent {hardirq-on-W} -> {in-hardirq-W} usage.
+[  369.149855] swapper/0 [HC1[1]:SC0[0]:HE0:SE1] takes:
+[  369.154890]  (&cdev->lock){+-..}, at: [<bf1979f0>] composite_disconnect+0x1c/0]
+[  369.163404] {hardirq-on-W} state was registered at:
+[  369.168348]   [<c00788a8>] __lock_acquire+0x5d0/0x7d8
+[  369.173506]   [<c0078b14>] lock_acquire+0x64/0x78
+[  369.178266]   [<c0263a34>] _spin_lock+0x4c/0x80
+[  369.182905]   [<bf19597c>] usb_function_deactivate+0x20/0x70 [g_nokia]
+[  369.189527]   [<bf1a0a88>] 0xbf1a0a88
+[  369.193281]   [<bf19f450>] 0xbf19f450
+[  369.197004]   [<bf19fa3c>] 0xbf19fa3c
+[  369.200758]   [<bf1a03a0>] 0xbf1a03a0
+[  369.204481]   [<bf19f254>] 0xbf19f254
+[  369.208204]   [<bf1a0158>] 0xbf1a0158
+[  369.211927]   [<bf1a130c>] 0xbf1a130c
+[  369.215650]   [<c01c21f0>] usb_gadget_register_driver+0x12c/0x28c
+[  369.221846]   [<bf1a06bc>] 0xbf1a06bc
+[  369.225569]   [<bf1a06e8>] 0xbf1a06e8
+[  369.229322]   [<c002c2dc>] __exception_text_end+0x64/0x19c
+[  369.234877]   [<c0081628>] sys_init_module+0x9c/0x194
+[  369.240004]   [<c002c8e0>] ret_fast_syscall+0x0/0x2c
+[  369.245039]   [<ffffffff>] 0xffffffff
+[  369.248793] irq event stamp: 218356
+[  369.252302] hardirqs last  enabled at (218355): [<c003a77c>] omap3_enter_idle+8
+[  369.260420] hardirqs last disabled at (218356): [<c0264774>] __irq_svc+0x34/0x0
+[  369.267927] softirqs last  enabled at (218348): [<c00585a4>] __do_softirq+0x134
+[  369.275892] softirqs last disabled at (218335): [<c005899c>] irq_exit+0x60/0xb0
+[  369.283308]
+[  369.283308] other info that might help us debug this:
+[  369.289930] no locks held by swapper/0.
+
+Cc: David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
+Signed-off-by: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
+---
+ drivers/usb/gadget/composite.c |    5 +++--
+ 1 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
+index 5d11c29..40f1da7 100644
+--- a/drivers/usb/gadget/composite.c
++++ b/drivers/usb/gadget/composite.c
+@@ -149,16 +149,17 @@ done:
+ int usb_function_deactivate(struct usb_function *function)
+ {
+       struct usb_composite_dev        *cdev = function->config->cdev;
++      unsigned long                   flags;
+       int                             status = 0;
+-      spin_lock(&cdev->lock);
++      spin_lock_irqsave(&cdev->lock, flags);
+       if (cdev->deactivations == 0)
+               status = usb_gadget_disconnect(cdev->gadget);
+       if (status == 0)
+               cdev->deactivations++;
+-      spin_unlock(&cdev->lock);
++      spin_unlock_irqrestore(&cdev->lock, flags);
+       return status;
+ }
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch
new file mode 100644 (file)
index 0000000..fadad9e
--- /dev/null
@@ -0,0 +1,218 @@
+From ba7b26e69f4bb41f10be444c5fded853330f82b5 Mon Sep 17 00:00:00 2001
+From: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
+Date: Tue, 24 Mar 2009 17:22:51 -0700
+Subject: [PATCH] USB: musb: NAK timeout scheme on bulk RX endpoint
+
+Fixes endpoint starvation issue when more than one bulk QH is
+multiplexed on the reserved bulk RX endpoint, which is normal
+for cases like serial and ethernet adapters.
+
+This patch sets the NAK timeout interval for such QHs, and when
+a timeout triggers the next QH will be scheduled.  (This resembles
+the bulk scheduling done in hardware by EHCI, OHCI, and UHCI.)
+
+This scheme doesn't work for devices which are connected to a
+high to full speed tree (transaction translator) as there is
+no NAK timeout interrupt from the musb controller from such
+devices.
+
+Tested with PIO, Inventra DMA, CPPI DMA.
+
+[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org:  fold in start_urb() update;
+  clarify only for bulk RX; don't accidentally clear WZC bits ]
+
+Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
+Cc: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |  112 ++++++++++++++++++++++++++++++++----------
+ 1 files changed, 85 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index 6dbbd07..bd1d5ae 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -64,11 +64,8 @@
+  *
+  * - DMA (Mentor/OMAP) ...has at least toggle update problems
+  *
+- * - Still no traffic scheduling code to make NAKing for bulk or control
+- *   transfers unable to starve other requests; or to make efficient use
+- *   of hardware with periodic transfers.  (Note that network drivers
+- *   commonly post bulk reads that stay pending for a long time; these
+- *   would make very visible trouble.)
++ * - [23-feb-2009] minimal traffic scheduling to avoid bulk RX packet
++ *   starvation ... nothing yet for TX, interrupt, or bulk.
+  *
+  * - Not tested with HNP, but some SRP paths seem to behave.
+  *
+@@ -88,11 +85,8 @@
+  *
+  * CONTROL transfers all go through ep0.  BULK ones go through dedicated IN
+  * and OUT endpoints ... hardware is dedicated for those "async" queue(s).
+- *
+  * (Yes, bulk _could_ use more of the endpoints than that, and would even
+- * benefit from it ... one remote device may easily be NAKing while others
+- * need to perform transfers in that same direction.  The same thing could
+- * be done in software though, assuming dma cooperates.)
++ * benefit from it.)
+  *
+  * INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints.
+  * So far that scheduling is both dumb and optimistic:  the endpoint will be
+@@ -201,8 +195,9 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+               len = urb->iso_frame_desc[0].length;
+               break;
+       default:                /* bulk, interrupt */
+-              buf = urb->transfer_buffer;
+-              len = urb->transfer_buffer_length;
++              /* actual_length may be nonzero on retry paths */
++              buf = urb->transfer_buffer + urb->actual_length;
++              len = urb->transfer_buffer_length - urb->actual_length;
+       }
+       DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
+@@ -1045,7 +1040,8 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
+               /* NOTE:  this code path would be a good place to PAUSE a
+                * control transfer, if another one is queued, so that
+-               * ep0 is more likely to stay busy.
++               * ep0 is more likely to stay busy.  That's already done
++               * for bulk RX transfers.
+                *
+                * if (qh->ring.next != &musb->control), then
+                * we have a candidate... NAKing is *NOT* an error
+@@ -1197,6 +1193,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+               /* NOTE:  this code path would be a good place to PAUSE a
+                * transfer, if there's some other (nonperiodic) tx urb
+                * that could use this fifo.  (dma complicates it...)
++               * That's already done for bulk RX transfers.
+                *
+                * if (bulk && qh->ring.next != &musb->out_bulk), then
+                * we have a candidate... NAKing is *NOT* an error
+@@ -1358,6 +1355,50 @@ finish:
+ #endif
++/* Schedule next QH from musb->in_bulk and move the current qh to
++ * the end; avoids starvation for other endpoints.
++ */
++static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
++{
++      struct dma_channel      *dma;
++      struct urb              *urb;
++      void __iomem            *mbase = musb->mregs;
++      void __iomem            *epio = ep->regs;
++      struct musb_qh          *cur_qh, *next_qh;
++      u16                     rx_csr;
++
++      musb_ep_select(mbase, ep->epnum);
++      dma = is_dma_capable() ? ep->rx_channel : NULL;
++
++      /* clear nak timeout bit */
++      rx_csr = musb_readw(epio, MUSB_RXCSR);
++      rx_csr |= MUSB_RXCSR_H_WZC_BITS;
++      rx_csr &= ~MUSB_RXCSR_DATAERROR;
++      musb_writew(epio, MUSB_RXCSR, rx_csr);
++
++      cur_qh = first_qh(&musb->in_bulk);
++      if (cur_qh) {
++              urb = next_urb(cur_qh);
++              if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
++                      dma->status = MUSB_DMA_STATUS_CORE_ABORT;
++                      musb->dma_controller->channel_abort(dma);
++                      urb->actual_length += dma->actual_len;
++                      dma->actual_len = 0L;
++              }
++              musb_save_toggle(ep, 1, urb);
++
++              /* move cur_qh to end of queue */
++              list_move_tail(&cur_qh->ring, &musb->in_bulk);
++
++              /* get the next qh from musb->in_bulk */
++              next_qh = first_qh(&musb->in_bulk);
++
++              /* set rx_reinit and schedule the next qh */
++              ep->rx_reinit = 1;
++              musb_start_urb(musb, 1, next_qh);
++      }
++}
++
+ /*
+  * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
+  * and high-bandwidth IN transfer cases.
+@@ -1421,18 +1462,26 @@ void musb_host_rx(struct musb *musb, u8 epnum)
+       } else if (rx_csr & MUSB_RXCSR_DATAERROR) {
+               if (USB_ENDPOINT_XFER_ISOC != qh->type) {
+-                      /* NOTE this code path would be a good place to PAUSE a
+-                       * transfer, if there's some other (nonperiodic) rx urb
+-                       * that could use this fifo.  (dma complicates it...)
++                      DBG(6, "RX end %d NAK timeout\n", epnum);
++
++                      /* NOTE: NAKing is *NOT* an error, so we want to
++                       * continue.  Except ... if there's a request for
++                       * another QH, use that instead of starving it.
+                        *
+-                       * if (bulk && qh->ring.next != &musb->in_bulk), then
+-                       * we have a candidate... NAKing is *NOT* an error
++                       * Devices like Ethernet and serial adapters keep
++                       * reads posted at all times, which will starve
++                       * other devices without this logic.
+                        */
+-                      DBG(6, "RX end %d NAK timeout\n", epnum);
++                      if (usb_pipebulk(urb->pipe)
++                                      && qh->mux == 1
++                                      && !list_is_singular(&musb->in_bulk)) {
++                              musb_bulk_rx_nak_timeout(musb, hw_ep);
++                              return;
++                      }
+                       musb_ep_select(mbase, epnum);
+-                      musb_writew(epio, MUSB_RXCSR,
+-                                      MUSB_RXCSR_H_WZC_BITS
+-                                      | MUSB_RXCSR_H_REQPKT);
++                      rx_csr |= MUSB_RXCSR_H_WZC_BITS;
++                      rx_csr &= ~MUSB_RXCSR_DATAERROR;
++                      musb_writew(epio, MUSB_RXCSR, rx_csr);
+                       goto finish;
+               } else {
+@@ -1756,6 +1805,17 @@ static int musb_schedule(
+                       head = &musb->in_bulk;
+               else
+                       head = &musb->out_bulk;
++
++              /* Enable bulk RX NAK timeout scheme when bulk requests are
++               * multiplexed.  This scheme doen't work in high speed to full
++               * speed scenario as NAK interrupts are not coming from a
++               * full speed device connected to a high speed device.
++               * NAK timeout interval is 8 (128 uframe or 16ms) for HS and
++               * 4 (8 frame or 8ms) for FS device.
++               */
++              if (is_in && qh->dev)
++                      qh->intv_reg =
++                              (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
+               goto success;
+       } else if (best_end < 0) {
+               return -ENOSPC;
+@@ -1888,13 +1948,11 @@ static int musb_urb_enqueue(
+                *
+                * The downside of disabling this is that transfer scheduling
+                * gets VERY unfair for nonperiodic transfers; a misbehaving
+-               * peripheral could make that hurt.  Or for reads, one that's
+-               * perfectly normal:  network and other drivers keep reads
+-               * posted at all times, having one pending for a week should
+-               * be perfectly safe.
++               * peripheral could make that hurt.  That's perfectly normal
++               * for reads from network or serial adapters ... so we have
++               * partial NAKlimit support for bulk RX.
+                *
+-               * The upside of disabling it is avoidng transfer scheduling
+-               * code to put this aside for while.
++               * The upside of disabling it is simpler transfer scheduling.
+                */
+               interval = 0;
+       }
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch
new file mode 100644 (file)
index 0000000..438f11c
--- /dev/null
@@ -0,0 +1,106 @@
+From 9ebf351bcd28a89a0b1ba8d0496fffbc72421611 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Tue, 24 Mar 2009 17:22:50 -0700
+Subject: [PATCH] USB: musb: rewrite host periodic endpoint allocation
+
+The current MUSB host code doesn't make use of all the available
+FIFOs in for periodic transfers since it wrongly assumes the RX
+and TX sides of any given hw_ep always share one FIFO.
+
+Change:  use 'in_qh' and 'out_qh' fields of the 'struct musb_hw_ep'
+to check the endpoint's business; get rid of the now-unused 'periodic'
+array in the 'struct musb'.  Also optimize a loop induction variable
+in the endpoint lookup code.
+
+(Based on a previous patch from Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>)
+
+[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: clarify description and origin
+  of this fix; whitespace ]
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Cc: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
+---
+ drivers/usb/musb/musb_core.h |    1 -
+ drivers/usb/musb/musb_host.c |   28 +++++++++++-----------------
+ 2 files changed, 11 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
+index 630946a..adf1806 100644
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -331,7 +331,6 @@ struct musb {
+       struct list_head        control;        /* of musb_qh */
+       struct list_head        in_bulk;        /* of musb_qh */
+       struct list_head        out_bulk;       /* of musb_qh */
+-      struct musb_qh          *periodic[32];  /* tree of interrupt+iso */
+ #endif
+       /* called with IRQs blocked; ON/nonzero implies starting a session,
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index bd1d5ae..499c431 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -390,7 +390,6 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+                        * de-allocated if it's tracked and allocated;
+                        * and where we'd update the schedule tree...
+                        */
+-                      musb->periodic[ep->epnum] = NULL;
+                       kfree(qh);
+                       qh = NULL;
+                       break;
+@@ -1760,31 +1759,27 @@ static int musb_schedule(
+       /* else, periodic transfers get muxed to other endpoints */
+-      /* FIXME this doesn't consider direction, so it can only
+-       * work for one half of the endpoint hardware, and assumes
+-       * the previous cases handled all non-shared endpoints...
+-       */
+-
+-      /* we know this qh hasn't been scheduled, so all we need to do
++      /*
++       * We know this qh hasn't been scheduled, so all we need to do
+        * is choose which hardware endpoint to put it on ...
+        *
+        * REVISIT what we really want here is a regular schedule tree
+-       * like e.g. OHCI uses, but for now musb->periodic is just an
+-       * array of the _single_ logical endpoint associated with a
+-       * given physical one (identity mapping logical->physical).
+-       *
+-       * that simplistic approach makes TT scheduling a lot simpler;
+-       * there is none, and thus none of its complexity...
++       * like e.g. OHCI uses.
+        */
+       best_diff = 4096;
+       best_end = -1;
+-      for (epnum = 1; epnum < musb->nr_endpoints; epnum++) {
++      for (epnum = 1, hw_ep = musb->endpoints + 1;
++                      epnum < musb->nr_endpoints;
++                      epnum++, hw_ep++) {
+               int     diff;
+-              if (musb->periodic[epnum])
++              if (is_in || hw_ep->is_shared_fifo) {
++                      if (hw_ep->in_qh  != NULL)
++                              continue;
++              } else  if (hw_ep->out_qh != NULL)
+                       continue;
+-              hw_ep = &musb->endpoints[epnum];
++
+               if (hw_ep == musb->bulk_ep)
+                       continue;
+@@ -1824,7 +1819,6 @@ static int musb_schedule(
+       idle = 1;
+       qh->mux = 0;
+       hw_ep = musb->endpoints + best_end;
+-      musb->periodic[best_end] = qh;
+       DBG(4, "qh %p periodic slot %d\n", qh, best_end);
+ success:
+       if (head) {
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch
new file mode 100644 (file)
index 0000000..db3481b
--- /dev/null
@@ -0,0 +1,181 @@
+From 60e7ce93befe795357db05001fe4caab522a421d Mon Sep 17 00:00:00 2001
+From: Jouni Hogander <jouni.hogander-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+Date: Tue, 24 Mar 2009 17:22:57 -0700
+Subject: [PATCH] USB: TWL: disable VUSB regulators when cable unplugged
+
+This patch disables USB regulators VUSB1V5, VUSB1V8, and VUSB3V1
+when the USB cable is unplugged to reduce power consumption.
+Added a depencency from twl4030 usb driver to TWL_REGULATOR.
+
+Signed-off-by: Jouni Hogander <jouni.hogander-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+Signed-off-by: Kalle Jokiniemi <kalle.jokiniemi-sMOQStClEysAvxtiuMwx3w@public.gmane.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
+---
+ drivers/usb/otg/Kconfig       |    2 +-
+ drivers/usb/otg/twl4030-usb.c |   73 ++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 65 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
+index ee55b44..5790a5b 100644
+--- a/drivers/usb/otg/Kconfig
++++ b/drivers/usb/otg/Kconfig
+@@ -43,7 +43,7 @@ config ISP1301_OMAP
+ config TWL4030_USB
+       tristate "TWL4030 USB Transceiver Driver"
+-      depends on TWL4030_CORE
++      depends on TWL4030_CORE && REGULATOR_TWL4030
+       select USB_OTG_UTILS
+       help
+         Enable this to support the USB OTG transceiver on TWL4030
+diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
+index 416e441..d9478d0 100644
+--- a/drivers/usb/otg/twl4030-usb.c
++++ b/drivers/usb/otg/twl4030-usb.c
+@@ -34,6 +34,8 @@
+ #include <linux/delay.h>
+ #include <linux/usb/otg.h>
+ #include <linux/i2c/twl4030.h>
++#include <linux/regulator/consumer.h>
++#include <linux/err.h>
+ /* Register defines */
+@@ -246,6 +248,11 @@ struct twl4030_usb {
+       struct otg_transceiver  otg;
+       struct device           *dev;
++      /* TWL4030 internal USB regulator supplies */
++      struct regulator        *usb1v5;
++      struct regulator        *usb1v8;
++      struct regulator        *usb3v1;
++
+       /* for vbus reporting with irqs disabled */
+       spinlock_t              lock;
+@@ -434,6 +441,18 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
+       pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
+       if (on) {
++              regulator_enable(twl->usb3v1);
++              regulator_enable(twl->usb1v8);
++              /*
++               * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
++               * in twl4030) resets the VUSB_DEDICATED2 register. This reset
++               * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to
++               * SLEEP. We work around this by clearing the bit after usv3v1
++               * is re-activated. This ensures that VUSB3V1 is really active.
++               */
++              twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
++                                                      VUSB_DEDICATED2);
++              regulator_enable(twl->usb1v5);
+               pwr &= ~PHY_PWR_PHYPWD;
+               WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+               twl4030_usb_write(twl, PHY_CLK_CTRL,
+@@ -443,6 +462,9 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
+       } else  {
+               pwr |= PHY_PWR_PHYPWD;
+               WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
++              regulator_disable(twl->usb1v5);
++              regulator_disable(twl->usb1v8);
++              regulator_disable(twl->usb3v1);
+       }
+ }
+@@ -468,7 +490,7 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
+       twl->asleep = 0;
+ }
+-static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
++static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
+ {
+       /* Enable writing to power configuration registers */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
+@@ -480,20 +502,45 @@ static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
+       /* input to VUSB3V1 LDO is from VBAT, not VBUS */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
+-      /* turn on 3.1V regulator */
+-      twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
++      /* Initialize 3.1V regulator */
++      twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
++
++      twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
++      if (IS_ERR(twl->usb3v1))
++              return -ENODEV;
++
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
+-      /* turn on 1.5V regulator */
+-      twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
++      /* Initialize 1.5V regulator */
++      twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
++
++      twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
++      if (IS_ERR(twl->usb1v5))
++              goto fail1;
++
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
+-      /* turn on 1.8V regulator */
+-      twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
++      /* Initialize 1.8V regulator */
++      twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
++
++      twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
++      if (IS_ERR(twl->usb1v8))
++              goto fail2;
++
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
+       /* disable access to power configuration registers */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
++
++      return 0;
++
++fail2:
++      regulator_put(twl->usb1v5);
++      twl->usb1v5 = NULL;
++fail1:
++      regulator_put(twl->usb3v1);
++      twl->usb3v1 = NULL;
++      return -ENODEV;
+ }
+ static ssize_t twl4030_usb_vbus_show(struct device *dev,
+@@ -598,7 +645,7 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
+ {
+       struct twl4030_usb_data *pdata = pdev->dev.platform_data;
+       struct twl4030_usb      *twl;
+-      int                     status;
++      int                     status, err;
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "platform_data not available\n");
+@@ -622,7 +669,12 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
+       /* init spinlock for workqueue */
+       spin_lock_init(&twl->lock);
+-      twl4030_usb_ldo_init(twl);
++      err = twl4030_usb_ldo_init(twl);
++      if (err) {
++              dev_err(&pdev->dev, "ldo init failed\n");
++              kfree(twl);
++              return err;
++      }
+       otg_set_transceiver(&twl->otg);
+       platform_set_drvdata(pdev, twl);
+@@ -688,6 +740,9 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
+       twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+       twl4030_phy_power(twl, 0);
++      regulator_put(twl->usb1v5);
++      regulator_put(twl->usb1v8);
++      regulator_put(twl->usb3v1);
+       kfree(twl);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch
new file mode 100644 (file)
index 0000000..3f49a4d
--- /dev/null
@@ -0,0 +1,84 @@
+From 7eef82d231578140c6000d04846a48bdaf341a65 Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Tue, 24 Mar 2009 17:23:19 -0700
+Subject: [PATCH] USB: gadget: composite device-level suspend/resume hooks
+
+Address one open question in the composite gadget framework:
+Yes, we should have device-level suspend/resume callbacks
+in addition to the function-level ones.  We have at least one
+scenario (with gadget zero in OTG test mode) that's awkward
+to handle without it.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Cc: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
+---
+ drivers/usb/gadget/composite.c |    8 ++++++--
+ include/linux/usb/composite.h  |    8 ++++++++
+ 2 files changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
+index 40f1da7..59e8523 100644
+--- a/drivers/usb/gadget/composite.c
++++ b/drivers/usb/gadget/composite.c
+@@ -1014,7 +1014,7 @@ composite_suspend(struct usb_gadget *gadget)
+       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+       struct usb_function             *f;
+-      /* REVISIT:  should we have config and device level
++      /* REVISIT:  should we have config level
+        * suspend/resume callbacks?
+        */
+       DBG(cdev, "suspend\n");
+@@ -1024,6 +1024,8 @@ composite_suspend(struct usb_gadget *gadget)
+                               f->suspend(f);
+               }
+       }
++      if (composite->suspend)
++              composite->suspend(cdev);
+ }
+ static void
+@@ -1032,10 +1034,12 @@ composite_resume(struct usb_gadget *gadget)
+       struct usb_composite_dev        *cdev = get_gadget_data(gadget);
+       struct usb_function             *f;
+-      /* REVISIT:  should we have config and device level
++      /* REVISIT:  should we have config level
+        * suspend/resume callbacks?
+        */
+       DBG(cdev, "resume\n");
++      if (composite->resume)
++              composite->resume(cdev);
+       if (cdev->config) {
+               list_for_each_entry(f, &cdev->config->functions, list) {
+                       if (f->resume)
+diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
+index 935c380..acd7b0f 100644
+--- a/include/linux/usb/composite.h
++++ b/include/linux/usb/composite.h
+@@ -244,6 +244,10 @@ int usb_add_config(struct usb_composite_dev *,
+  *    value; it should return zero on successful initialization.
+  * @unbind: Reverses @bind(); called as a side effect of unregistering
+  *    this driver.
++ * @suspend: Notifies when the host stops sending USB traffic,
++ *    after function notifications
++ * @resume: Notifies configuration when the host restarts USB traffic,
++ *    before function notifications
+  *
+  * Devices default to reporting self powered operation.  Devices which rely
+  * on bus powered operation should report this in their @bind() method.
+@@ -268,6 +272,10 @@ struct usb_composite_driver {
+       int                     (*bind)(struct usb_composite_dev *);
+       int                     (*unbind)(struct usb_composite_dev *);
++
++      /* global suspend hooks */
++      void                    (*suspend)(struct usb_composite_dev *);
++      void                    (*resume)(struct usb_composite_dev *);
+ };
+ extern int usb_composite_register(struct usb_composite_driver *);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch
new file mode 100644 (file)
index 0000000..a89bc2f
--- /dev/null
@@ -0,0 +1,47 @@
+From 00c4bd07a64061ec9ab9c35f5bf01ec6187138f4 Mon Sep 17 00:00:00 2001
+From: Jonathan McDowell <noodles-4QvXXjU8Dv4@public.gmane.org>
+Date: Thu, 26 Mar 2009 00:45:27 -0700
+Subject: [PATCH] usb gadget: fix ethernet link reports to ethtool
+
+The g_ether USB gadget driver currently decides whether or not there's a
+link to report back for eth_get_link based on if the USB link speed is
+set. The USB gadget speed is however often set even before the device is
+enumerated. It seems more sensible to only report a "link" if we're
+actually connected to a host that wants to talk to us. The patch below
+does this for me - tested with the PXA27x UDC driver.
+
+Signed-Off-By: Jonathan McDowell <noodles-4QvXXjU8Dv4@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/gadget/u_ether.c |    8 +-------
+ 1 files changed, 1 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
+index 96d65ca..4007770 100644
+--- a/drivers/usb/gadget/u_ether.c
++++ b/drivers/usb/gadget/u_ether.c
+@@ -175,12 +175,6 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
+       strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
+ }
+-static u32 eth_get_link(struct net_device *net)
+-{
+-      struct eth_dev  *dev = netdev_priv(net);
+-      return dev->gadget->speed != USB_SPEED_UNKNOWN;
+-}
+-
+ /* REVISIT can also support:
+  *   - WOL (by tracking suspends and issuing remote wakeup)
+  *   - msglevel (implies updated messaging)
+@@ -189,7 +183,7 @@ static u32 eth_get_link(struct net_device *net)
+ static struct ethtool_ops ops = {
+       .get_drvinfo = eth_get_drvinfo,
+-      .get_link = eth_get_link
++      .get_link = ethtool_op_get_link,
+ };
+ static void defer_kevent(struct eth_dev *dev, int flag)
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch
new file mode 100644 (file)
index 0000000..8627825
--- /dev/null
@@ -0,0 +1,60 @@
+From c3b527a21104b6bb61558fba6c65aa80f63e0772 Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Thu, 26 Mar 2009 17:36:57 -0700
+Subject: [PATCH] usb: musb_host, minor enqueue locking fix (v2)
+
+Someone noted that the enqueue path used an unlocked access
+for usb_host_endpoint->hcpriv ... fix that, by being safe
+and always accessing it under spinlock protection.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |   17 ++++++++---------
+ 1 files changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index 499c431..ff09595 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -1841,7 +1841,7 @@ static int musb_urb_enqueue(
+       unsigned long                   flags;
+       struct musb                     *musb = hcd_to_musb(hcd);
+       struct usb_host_endpoint        *hep = urb->ep;
+-      struct musb_qh                  *qh = hep->hcpriv;
++      struct musb_qh                  *qh;
+       struct usb_endpoint_descriptor  *epd = &hep->desc;
+       int                             ret;
+       unsigned                        type_reg;
+@@ -1853,22 +1853,21 @@ static int musb_urb_enqueue(
+       spin_lock_irqsave(&musb->lock, flags);
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
++      qh = ret ? NULL : hep->hcpriv;
++      if (qh)
++              urb->hcpriv = qh;
+       spin_unlock_irqrestore(&musb->lock, flags);
+-      if (ret)
+-              return ret;
+       /* DMA mapping was already done, if needed, and this urb is on
+-       * hep->urb_list ... so there's little to do unless hep wasn't
+-       * yet scheduled onto a live qh.
++       * hep->urb_list now ... so we're done, unless hep wasn't yet
++       * scheduled onto a live qh.
+        *
+        * REVISIT best to keep hep->hcpriv valid until the endpoint gets
+        * disabled, testing for empty qh->ring and avoiding qh setup costs
+        * except for the first urb queued after a config change.
+        */
+-      if (qh) {
+-              urb->hcpriv = qh;
+-              return 0;
+-      }
++      if (qh || ret)
++              return ret;
+       /* Allocate and initialize qh, minimizing the work done each time
+        * hw_ep gets reprogrammed, or with irqs blocked.  Then schedule it.
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch
new file mode 100644 (file)
index 0000000..09fc0a1
--- /dev/null
@@ -0,0 +1,93 @@
+From 48ce47b15bfd420982ee275c595a9139eb6fabf7 Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Thu, 26 Mar 2009 17:38:30 -0700
+Subject: [PATCH] usb: musb_host, fix ep0 fifo flushing
+
+The MUSB host side can't share generic TX FIFO flush logic
+with EP0; the EP0 TX status register bits are different
+from those for other entpoints.
+
+Resolve this issue by providing a new EP0-specific routine
+to flush and reset the FIFO, which pays careful attention to
+restrictions listed in the latest programmer's guide.  This
+gets rid of an open issue whereby the usbtest control write
+test (#14) failed.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |   38 +++++++++++++++++++++++++-------------
+ 1 files changed, 25 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index ff09595..a5d75aa 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -125,6 +125,29 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
+       }
+ }
++static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep)
++{
++      void __iomem    *epio = ep->regs;
++      u16             csr;
++      int             retries = 5;
++
++      /* scrub any data left in the fifo */
++      do {
++              csr = musb_readw(epio, MUSB_TXCSR);
++              if (!(csr & (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_RXPKTRDY)))
++                      break;
++              musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO);
++              csr = musb_readw(epio, MUSB_TXCSR);
++              udelay(10);
++      } while (--retries);
++
++      WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n",
++                      ep->epnum, csr);
++
++      /* and reset for the next transfer */
++      musb_writew(epio, MUSB_TXCSR, 0);
++}
++
+ /*
+  * Start transmit. Caller is responsible for locking shared resources.
+  * musb must be locked.
+@@ -693,11 +716,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+                       musb_writew(epio, MUSB_TXCSR, csr);
+                       csr = musb_readw(epio, MUSB_TXCSR);
+               } else {
+-                      /* endpoint 0: just flush */
+-                      musb_writew(epio, MUSB_CSR0,
+-                              csr | MUSB_CSR0_FLUSHFIFO);
+-                      musb_writew(epio, MUSB_CSR0,
+-                              csr | MUSB_CSR0_FLUSHFIFO);
++                      musb_h_ep0_flush_fifo(hw_ep);
+               }
+               /* target addr and (for multipoint) hub addr/port */
+@@ -1063,11 +1082,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
+                       csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
+                       musb_writew(epio, MUSB_CSR0, csr);
+               } else {
+-                      csr |= MUSB_CSR0_FLUSHFIFO;
+-                      musb_writew(epio, MUSB_CSR0, csr);
+-                      musb_writew(epio, MUSB_CSR0, csr);
+-                      csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
+-                      musb_writew(epio, MUSB_CSR0, csr);
++                      musb_h_ep0_flush_fifo(hw_ep);
+               }
+               musb_writeb(epio, MUSB_NAKLIMIT0, 0);
+@@ -1081,9 +1096,6 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
+                * SHOULD NEVER HAPPEN! */
+               ERR("no URB for end 0\n");
+-              musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
+-              musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
+-              musb_writew(epio, MUSB_CSR0, 0);
+               goto done;
+       }
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch
new file mode 100644 (file)
index 0000000..bcbe3bb
--- /dev/null
@@ -0,0 +1,361 @@
+From c99f4a68268801a2e2ffbef9766c3ac89e4fb22c Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Thu, 26 Mar 2009 18:27:47 -0700
+Subject: [PATCH] musb: sanitize clearing TXCSR DMA bits (take 2)
+
+The MUSB code clears TXCSR_DMAMODE incorrectly in several
+places, either asserting that TXCSR_DMAENAB is clear (when
+sometimes it isn't) or clearing both bits together.  Recent
+versions of the programmer's guide require DMAENAB to be
+cleared first, although some older ones didn't.
+
+Fix this and while at it:
+
+ - In musb_gadget::txstate(), stop clearing the AUTOSET
+   and DMAMODE bits for the CPPI case since they never
+   get set anyway (the former bit is reserved on DaVinci);
+   but do clear the DMAENAB bit on the DMA error path.
+
+ - In musb_host::musb_ep_program(), remove the duplicate
+   DMA controller specific code code clearing the TXCSR
+   previous state, add the code to clear TXCSR DMA bits
+   on the Inventra DMA error path, to replace such code
+   (executed late) on the PIO path.
+
+ - In musbhsdma::dma_channel_abort()/dma_controller_irq(),
+   add/use the 'offset' variable to avoid MUSB_EP_OFFSET()
+   invocations on every RXCSR/TXCSR access.
+
+[dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: don't introduce CamelCase,
+shrink diff]
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_gadget.c |   33 +++++++++++------
+ drivers/usb/musb/musb_host.c   |   79 ++++++++++++++++------------------------
+ drivers/usb/musb/musbhsdma.c   |   59 ++++++++++++++++++------------
+ 3 files changed, 90 insertions(+), 81 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index c7ebd08..f79440c 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -165,9 +165,15 @@ static void nuke(struct musb_ep *ep, const int status)
+       if (is_dma_capable() && ep->dma) {
+               struct dma_controller   *c = ep->musb->dma_controller;
+               int value;
++
+               if (ep->is_in) {
++                      /*
++                       * The programming guide says that we must not clear
++                       * the DMAMODE bit before DMAENAB, so we only
++                       * clear it in the second write...
++                       */
+                       musb_writew(epio, MUSB_TXCSR,
+-                                      0 | MUSB_TXCSR_FLUSHFIFO);
++                                  MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO);
+                       musb_writew(epio, MUSB_TXCSR,
+                                       0 | MUSB_TXCSR_FLUSHFIFO);
+               } else {
+@@ -230,7 +236,7 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
+                 |     IN token(s) are recd from Host.
+                 |             -> DMA interrupt on completion
+                 |                calls TxAvail.
+-                |                   -> stop DMA, ~DmaEenab,
++                |                   -> stop DMA, ~DMAENAB,
+                 |                   -> set TxPktRdy for last short pkt or zlp
+                 |                   -> Complete Request
+                 |                   -> Continue next request (call txstate)
+@@ -315,9 +321,17 @@ static void txstate(struct musb *musb, struct musb_request *req)
+                                       request->dma, request_size);
+                       if (use_dma) {
+                               if (musb_ep->dma->desired_mode == 0) {
+-                                      /* ASSERT: DMAENAB is clear */
+-                                      csr &= ~(MUSB_TXCSR_AUTOSET |
+-                                                      MUSB_TXCSR_DMAMODE);
++                                      /*
++                                       * We must not clear the DMAMODE bit
++                                       * before the DMAENAB bit -- and the
++                                       * latter doesn't always get cleared
++                                       * before we get here...
++                                       */
++                                      csr &= ~(MUSB_TXCSR_AUTOSET
++                                              | MUSB_TXCSR_DMAENAB);
++                                      musb_writew(epio, MUSB_TXCSR, csr
++                                              | MUSB_TXCSR_P_WZC_BITS);
++                                      csr &= ~MUSB_TXCSR_DMAMODE;
+                                       csr |= (MUSB_TXCSR_DMAENAB |
+                                                       MUSB_TXCSR_MODE);
+                                       /* against programming guide */
+@@ -334,10 +348,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
+ #elif defined(CONFIG_USB_TI_CPPI_DMA)
+               /* program endpoint CSR first, then setup DMA */
+-              csr &= ~(MUSB_TXCSR_AUTOSET
+-                              | MUSB_TXCSR_DMAMODE
+-                              | MUSB_TXCSR_P_UNDERRUN
+-                              | MUSB_TXCSR_TXPKTRDY);
++              csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+               csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
+               musb_writew(epio, MUSB_TXCSR,
+                       (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
+@@ -364,8 +375,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
+               if (!use_dma) {
+                       c->channel_release(musb_ep->dma);
+                       musb_ep->dma = NULL;
+-                      /* ASSERT: DMAENAB clear */
+-                      csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE);
++                      csr &= ~MUSB_TXCSR_DMAENAB;
++                      musb_writew(epio, MUSB_TXCSR, csr);
+                       /* invariant: prequest->buf is non-null */
+               }
+ #elif defined(CONFIG_USB_TUSB_OMAP_DMA)
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index a5d75aa..6591282 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -590,10 +590,17 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+               csr = musb_readw(ep->regs, MUSB_TXCSR);
+               if (csr & MUSB_TXCSR_MODE) {
+                       musb_h_tx_flush_fifo(ep);
++                      csr = musb_readw(ep->regs, MUSB_TXCSR);
+                       musb_writew(ep->regs, MUSB_TXCSR,
+-                                      MUSB_TXCSR_FRCDATATOG);
++                                  csr | MUSB_TXCSR_FRCDATATOG);
+               }
+-              /* clear mode (and everything else) to enable Rx */
++
++              /*
++               * Clear the MODE bit (and everything else) to enable Rx.
++               * NOTE: we mustn't clear the DMAMODE bit before DMAENAB.
++               */
++              if (csr & MUSB_TXCSR_DMAMODE)
++                      musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE);
+               musb_writew(ep->regs, MUSB_TXCSR, 0);
+       /* scrub all previous state, clearing toggle */
+@@ -690,12 +697,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+               /* general endpoint setup */
+               if (epnum) {
+-                      /* ASSERT:  TXCSR_DMAENAB was already cleared */
+-
+                       /* flush all old state, set default */
+                       musb_h_tx_flush_fifo(hw_ep);
++
++                      /*
++                       * We must not clear the DMAMODE bit before or in
++                       * the same cycle with the DMAENAB bit, so we clear
++                       * the latter first...
++                       */
+                       csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT
+-                                      | MUSB_TXCSR_DMAMODE
++                                      | MUSB_TXCSR_AUTOSET
++                                      | MUSB_TXCSR_DMAENAB
+                                       | MUSB_TXCSR_FRCDATATOG
+                                       | MUSB_TXCSR_H_RXSTALL
+                                       | MUSB_TXCSR_H_ERROR
+@@ -703,16 +715,15 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+                                       );
+                       csr |= MUSB_TXCSR_MODE;
+-                      if (usb_gettoggle(urb->dev,
+-                                      qh->epnum, 1))
++                      if (usb_gettoggle(urb->dev, qh->epnum, 1))
+                               csr |= MUSB_TXCSR_H_WR_DATATOGGLE
+                                       | MUSB_TXCSR_H_DATATOGGLE;
+                       else
+                               csr |= MUSB_TXCSR_CLRDATATOG;
+-                      /* twice in case of double packet buffering */
+                       musb_writew(epio, MUSB_TXCSR, csr);
+                       /* REVISIT may need to clear FLUSHFIFO ... */
++                      csr &= ~MUSB_TXCSR_DMAMODE;
+                       musb_writew(epio, MUSB_TXCSR, csr);
+                       csr = musb_readw(epio, MUSB_TXCSR);
+               } else {
+@@ -755,34 +766,19 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+ #ifdef CONFIG_USB_INVENTRA_DMA
+               if (dma_channel) {
+-
+-                      /* clear previous state */
+-                      csr = musb_readw(epio, MUSB_TXCSR);
+-                      csr &= ~(MUSB_TXCSR_AUTOSET
+-                              | MUSB_TXCSR_DMAMODE
+-                              | MUSB_TXCSR_DMAENAB);
+-                      csr |= MUSB_TXCSR_MODE;
+-                      musb_writew(epio, MUSB_TXCSR,
+-                              csr | MUSB_TXCSR_MODE);
+-
+                       qh->segsize = min(len, dma_channel->max_len);
+-
+                       if (qh->segsize <= packet_sz)
+                               dma_channel->desired_mode = 0;
+                       else
+                               dma_channel->desired_mode = 1;
+-
+                       if (dma_channel->desired_mode == 0) {
+-                              csr &= ~(MUSB_TXCSR_AUTOSET
+-                                      | MUSB_TXCSR_DMAMODE);
++                              /* Against the programming guide */
+                               csr |= (MUSB_TXCSR_DMAENAB);
+-                                      /* against programming guide */
+                       } else
+                               csr |= (MUSB_TXCSR_AUTOSET
+                                       | MUSB_TXCSR_DMAENAB
+                                       | MUSB_TXCSR_DMAMODE);
+-
+                       musb_writew(epio, MUSB_TXCSR, csr);
+                       dma_ok = dma_controller->channel_program(
+@@ -799,6 +795,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+                               else
+                                       hw_ep->rx_channel = NULL;
+                               dma_channel = NULL;
++
++                              /*
++                               * The programming guide says that we must
++                               * clear the DMAENAB bit before DMAMODE...
++                               */
++                              csr = musb_readw(epio, MUSB_TXCSR);
++                              csr &= ~(MUSB_TXCSR_DMAENAB
++                                              | MUSB_TXCSR_AUTOSET);
++                              musb_writew(epio, MUSB_TXCSR, csr);
++                              csr &= ~MUSB_TXCSR_DMAMODE;
++                              musb_writew(epio, MUSB_TXCSR, csr);
+                       }
+               }
+ #endif
+@@ -806,18 +813,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+               /* candidate for DMA */
+               if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
+-                      /* program endpoint CSRs first, then setup DMA.
+-                       * assume CPPI setup succeeds.
+-                       * defer enabling dma.
+-                       */
+-                      csr = musb_readw(epio, MUSB_TXCSR);
+-                      csr &= ~(MUSB_TXCSR_AUTOSET
+-                                      | MUSB_TXCSR_DMAMODE
+-                                      | MUSB_TXCSR_DMAENAB);
+-                      csr |= MUSB_TXCSR_MODE;
+-                      musb_writew(epio, MUSB_TXCSR,
+-                              csr | MUSB_TXCSR_MODE);
+-
++                      /* Defer enabling DMA */
+                       dma_channel->actual_len = 0L;
+                       qh->segsize = len;
+@@ -846,20 +842,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+               }
+               if (load_count) {
+-                      /* ASSERT:  TXCSR_DMAENAB was already cleared */
+-
+                       /* PIO to load FIFO */
+                       qh->segsize = load_count;
+                       musb_write_fifo(hw_ep, load_count, buf);
+-                      csr = musb_readw(epio, MUSB_TXCSR);
+-                      csr &= ~(MUSB_TXCSR_DMAENAB
+-                              | MUSB_TXCSR_DMAMODE
+-                              | MUSB_TXCSR_AUTOSET);
+-                      /* write CSR */
+-                      csr |= MUSB_TXCSR_MODE;
+-
+-                      if (epnum)
+-                              musb_writew(epio, MUSB_TXCSR, csr);
+               }
+               /* re-enable interrupt */
+diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
+index 8662e9e..40709c3 100644
+--- a/drivers/usb/musb/musbhsdma.c
++++ b/drivers/usb/musb/musbhsdma.c
+@@ -195,30 +195,32 @@ static int dma_channel_abort(struct dma_channel *channel)
+       void __iomem *mbase = musb_channel->controller->base;
+       u8 bchannel = musb_channel->idx;
++      int offset;
+       u16 csr;
+       if (channel->status == MUSB_DMA_STATUS_BUSY) {
+               if (musb_channel->transmit) {
+-
+-                      csr = musb_readw(mbase,
+-                              MUSB_EP_OFFSET(musb_channel->epnum,
+-                                              MUSB_TXCSR));
+-                      csr &= ~(MUSB_TXCSR_AUTOSET |
+-                               MUSB_TXCSR_DMAENAB |
+-                               MUSB_TXCSR_DMAMODE);
+-                      musb_writew(mbase,
+-                              MUSB_EP_OFFSET(musb_channel->epnum, MUSB_TXCSR),
+-                              csr);
++                      offset = MUSB_EP_OFFSET(musb_channel->epnum,
++                                              MUSB_TXCSR);
++
++                      /*
++                       * The programming guide says that we must clear
++                       * the DMAENAB bit before the DMAMODE bit...
++                       */
++                      csr = musb_readw(mbase, offset);
++                      csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB);
++                      musb_writew(mbase, offset, csr);
++                      csr &= ~MUSB_TXCSR_DMAMODE;
++                      musb_writew(mbase, offset, csr);
+               } else {
+-                      csr = musb_readw(mbase,
+-                              MUSB_EP_OFFSET(musb_channel->epnum,
+-                                              MUSB_RXCSR));
++                      offset = MUSB_EP_OFFSET(musb_channel->epnum,
++                                              MUSB_RXCSR);
++
++                      csr = musb_readw(mbase, offset);
+                       csr &= ~(MUSB_RXCSR_AUTOCLEAR |
+                                MUSB_RXCSR_DMAENAB |
+                                MUSB_RXCSR_DMAMODE);
+-                      musb_writew(mbase,
+-                              MUSB_EP_OFFSET(musb_channel->epnum, MUSB_RXCSR),
+-                              csr);
++                      musb_writew(mbase, offset, csr);
+               }
+               musb_writew(mbase,
+@@ -296,14 +298,25 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
+                                       && ((channel->desired_mode == 0)
+                                           || (channel->actual_len &
+                                           (musb_channel->max_packet_sz - 1)))
+-                                       ) {
++                                  ) {
++                                      u8  epnum  = musb_channel->epnum;
++                                      int offset = MUSB_EP_OFFSET(epnum,
++                                                                  MUSB_TXCSR);
++                                      u16 txcsr;
++
++                                      /*
++                                       * The programming guide says that we
++                                       * must clear DMAENAB before DMAMODE.
++                                       */
++                                      musb_ep_select(mbase, epnum);
++                                      txcsr = musb_readw(mbase, offset);
++                                      txcsr &= ~(MUSB_TXCSR_DMAENAB
++                                                      | MUSB_TXCSR_AUTOSET);
++                                      musb_writew(mbase, offset, txcsr);
+                                       /* Send out the packet */
+-                                      musb_ep_select(mbase,
+-                                              musb_channel->epnum);
+-                                      musb_writew(mbase, MUSB_EP_OFFSET(
+-                                                      musb_channel->epnum,
+-                                                      MUSB_TXCSR),
+-                                              MUSB_TXCSR_TXPKTRDY);
++                                      txcsr &= ~MUSB_TXCSR_DMAMODE;
++                                      txcsr |=  MUSB_TXCSR_TXPKTRDY;
++                                      musb_writew(mbase, offset, txcsr);
+                               } else {
+                                       musb_dma_completion(
+                                               musb,
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch
new file mode 100644 (file)
index 0000000..7d546e1
--- /dev/null
@@ -0,0 +1,417 @@
+From 035cd4a26e9b1638b4b0419b98409026176563ca Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Thu, 26 Mar 2009 18:29:19 -0700
+Subject: [PATCH] musb: fix isochronous TXDMA (take 2)
+
+Multi-frame isochronous TX URBs transfers in DMA mode never
+complete with CPPI DMA because musb_host_tx() doesn't restart
+DMA on the second frame, only emitting a debug message.
+With Inventra DMA they complete, but in PIO mode.  To fix:
+
+ - Factor out programming of the DMA transfer from
+   musb_ep_program() into musb_tx_dma_program();
+
+ - Reorder the code at the end of musb_host_tx() to
+   facilitate the fallback to PIO iff DMA fails;
+
+ - Handle the buffer offset consistently for both
+   PIO and DMA modes;
+
+ - Add an argument to musb_ep_program() for the same
+   reason (it only worked correctly with non-zero
+   offset of the first frame in PIO mode);
+
+ - Set the completed isochronous frame descriptor's
+   'actual_length' and 'status' fields correctly in
+   DMA mode.
+
+Also, since CPPI reportedly doesn't like sending isochronous
+packets in the RNDIS mode, change the criterion for this
+mode to be used only for multi-packet transfers.  (There's
+no need for that mode in the single-packet case anyway.)
+
+[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: split comment paragraph
+into bullet list, shrink patch delta, style tweaks ]
+
+Signed-off-by: Pavel Kiryukhin <pkiryukhin-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/cppi_dma.c  |    1 +
+ drivers/usb/musb/musb_host.c |  227 +++++++++++++++++++-----------------------
+ 2 files changed, 105 insertions(+), 123 deletions(-)
+
+diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
+index 569ef0f..ac7227c 100644
+--- a/drivers/usb/musb/cppi_dma.c
++++ b/drivers/usb/musb/cppi_dma.c
+@@ -579,6 +579,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
+        * trigger the "send a ZLP?" confusion.
+        */
+       rndis = (maxpacket & 0x3f) == 0
++              && length > maxpacket
+               && length < 0xffff
+               && (length % maxpacket) != 0;
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index 6591282..f6e84a0 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -96,8 +96,8 @@
+ static void musb_ep_program(struct musb *musb, u8 epnum,
+-                      struct urb *urb, unsigned int nOut,
+-                      u8 *buf, u32 len);
++                      struct urb *urb, int is_out,
++                      u8 *buf, u32 offset, u32 len);
+ /*
+  * Clear TX fifo. Needed to avoid BABBLE errors.
+@@ -189,9 +189,10 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+ {
+       u16                     frame;
+       u32                     len;
+-      void                    *buf;
+       void __iomem            *mbase =  musb->mregs;
+       struct urb              *urb = next_urb(qh);
++      void                    *buf = urb->transfer_buffer;
++      u32                     offset = 0;
+       struct musb_hw_ep       *hw_ep = qh->hw_ep;
+       unsigned                pipe = urb->pipe;
+       u8                      address = usb_pipedevice(pipe);
+@@ -214,7 +215,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+       case USB_ENDPOINT_XFER_ISOC:
+               qh->iso_idx = 0;
+               qh->frame = 0;
+-              buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset;
++              offset = urb->iso_frame_desc[0].offset;
+               len = urb->iso_frame_desc[0].length;
+               break;
+       default:                /* bulk, interrupt */
+@@ -232,14 +233,14 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+                       case USB_ENDPOINT_XFER_ISOC:    s = "-iso"; break;
+                       default:                        s = "-intr"; break;
+                       }; s; }),
+-                      epnum, buf, len);
++                      epnum, buf + offset, len);
+       /* Configure endpoint */
+       if (is_in || hw_ep->is_shared_fifo)
+               hw_ep->in_qh = qh;
+       else
+               hw_ep->out_qh = qh;
+-      musb_ep_program(musb, epnum, urb, !is_in, buf, len);
++      musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len);
+       /* transmit may have more work: start it when it is time */
+       if (is_in)
+@@ -250,7 +251,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+       case USB_ENDPOINT_XFER_ISOC:
+       case USB_ENDPOINT_XFER_INT:
+               DBG(3, "check whether there's still time for periodic Tx\n");
+-              qh->iso_idx = 0;
+               frame = musb_readw(mbase, MUSB_FRAME);
+               /* FIXME this doesn't implement that scheduling policy ...
+                * or handle framecounter wrapping
+@@ -631,14 +631,68 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+       ep->rx_reinit = 0;
+ }
++static bool musb_tx_dma_program(struct dma_controller *dma,
++              struct musb_hw_ep *hw_ep, struct musb_qh *qh,
++              struct urb *urb, u32 offset, u32 length)
++{
++      struct dma_channel      *channel = hw_ep->tx_channel;
++      void __iomem            *epio = hw_ep->regs;
++      u16                     pkt_size = qh->maxpacket;
++      u16                     csr;
++      u8                      mode;
++
++#ifdef        CONFIG_USB_INVENTRA_DMA
++      if (length > channel->max_len)
++              length = channel->max_len;
++
++      csr = musb_readw(epio, MUSB_TXCSR);
++      if (length > pkt_size) {
++              mode = 1;
++              csr |= MUSB_TXCSR_AUTOSET
++                      | MUSB_TXCSR_DMAMODE
++                      | MUSB_TXCSR_DMAENAB;
++      } else {
++              mode = 0;
++              csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
++              csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
++      }
++      channel->desired_mode = mode;
++      musb_writew(epio, MUSB_TXCSR, csr);
++#else
++      if (!is_cppi_enabled() && !tusb_dma_omap())
++              return false;
++
++      channel->actual_len = 0;
++
++      /*
++       * TX uses "RNDIS" mode automatically but needs help
++       * to identify the zero-length-final-packet case.
++       */
++      mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0;
++#endif
++
++      qh->segsize = length;
++
++      if (!dma->channel_program(channel, pkt_size, mode,
++                      urb->transfer_dma + offset, length)) {
++              dma->channel_release(channel);
++              hw_ep->tx_channel = NULL;
++
++              csr = musb_readw(epio, MUSB_TXCSR);
++              csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB);
++              musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS);
++              return false;
++      }
++      return true;
++}
+ /*
+  * Program an HDRC endpoint as per the given URB
+  * Context: irqs blocked, controller lock held
+  */
+ static void musb_ep_program(struct musb *musb, u8 epnum,
+-                      struct urb *urb, unsigned int is_out,
+-                      u8 *buf, u32 len)
++                      struct urb *urb, int is_out,
++                      u8 *buf, u32 offset, u32 len)
+ {
+       struct dma_controller   *dma_controller;
+       struct dma_channel      *dma_channel;
+@@ -764,82 +818,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+               else
+                       load_count = min((u32) packet_sz, len);
+-#ifdef CONFIG_USB_INVENTRA_DMA
+-              if (dma_channel) {
+-                      qh->segsize = min(len, dma_channel->max_len);
+-                      if (qh->segsize <= packet_sz)
+-                              dma_channel->desired_mode = 0;
+-                      else
+-                              dma_channel->desired_mode = 1;
+-
+-                      if (dma_channel->desired_mode == 0) {
+-                              /* Against the programming guide */
+-                              csr |= (MUSB_TXCSR_DMAENAB);
+-                      } else
+-                              csr |= (MUSB_TXCSR_AUTOSET
+-                                      | MUSB_TXCSR_DMAENAB
+-                                      | MUSB_TXCSR_DMAMODE);
+-                      musb_writew(epio, MUSB_TXCSR, csr);
+-
+-                      dma_ok = dma_controller->channel_program(
+-                                      dma_channel, packet_sz,
+-                                      dma_channel->desired_mode,
+-                                      urb->transfer_dma,
+-                                      qh->segsize);
+-                      if (dma_ok) {
+-                              load_count = 0;
+-                      } else {
+-                              dma_controller->channel_release(dma_channel);
+-                              if (is_out)
+-                                      hw_ep->tx_channel = NULL;
+-                              else
+-                                      hw_ep->rx_channel = NULL;
+-                              dma_channel = NULL;
+-
+-                              /*
+-                               * The programming guide says that we must
+-                               * clear the DMAENAB bit before DMAMODE...
+-                               */
+-                              csr = musb_readw(epio, MUSB_TXCSR);
+-                              csr &= ~(MUSB_TXCSR_DMAENAB
+-                                              | MUSB_TXCSR_AUTOSET);
+-                              musb_writew(epio, MUSB_TXCSR, csr);
+-                              csr &= ~MUSB_TXCSR_DMAMODE;
+-                              musb_writew(epio, MUSB_TXCSR, csr);
+-                      }
+-              }
+-#endif
+-
+-              /* candidate for DMA */
+-              if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
+-
+-                      /* Defer enabling DMA */
+-                      dma_channel->actual_len = 0L;
+-                      qh->segsize = len;
+-
+-                      /* TX uses "rndis" mode automatically, but needs help
+-                       * to identify the zero-length-final-packet case.
+-                       */
+-                      dma_ok = dma_controller->channel_program(
+-                                      dma_channel, packet_sz,
+-                                      (urb->transfer_flags
+-                                                      & URB_ZERO_PACKET)
+-                                              == URB_ZERO_PACKET,
+-                                      urb->transfer_dma,
+-                                      qh->segsize);
+-                      if (dma_ok) {
+-                              load_count = 0;
+-                      } else {
+-                              dma_controller->channel_release(dma_channel);
+-                              hw_ep->tx_channel = NULL;
+-                              dma_channel = NULL;
+-
+-                              /* REVISIT there's an error path here that
+-                               * needs handling:  can't do dma, but
+-                               * there's no pio buffer address...
+-                               */
+-                      }
+-              }
++              if (dma_channel && musb_tx_dma_program(dma_controller,
++                                      hw_ep, qh, urb, offset, len))
++                      load_count = 0;
+               if (load_count) {
+                       /* PIO to load FIFO */
+@@ -899,7 +880,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+                                               dma_channel, packet_sz,
+                                               !(urb->transfer_flags
+                                                       & URB_SHORT_NOT_OK),
+-                                              urb->transfer_dma,
++                                              urb->transfer_dma + offset,
+                                               qh->segsize);
+                               if (!dma_ok) {
+                                       dma_controller->channel_release(
+@@ -1142,8 +1123,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+       int                     pipe;
+       bool                    done = false;
+       u16                     tx_csr;
+-      size_t                  wLength = 0;
+-      u8                      *buf = NULL;
++      size_t                  length = 0;
++      size_t                  offset = 0;
+       struct urb              *urb;
+       struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
+       void __iomem            *epio = hw_ep->regs;
+@@ -1161,7 +1142,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+       /* with CPPI, DMA sometimes triggers "extra" irqs */
+       if (!urb) {
+               DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
+-              goto finish;
++              return;
+       }
+       pipe = urb->pipe;
+@@ -1198,7 +1179,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+               musb_writew(epio, MUSB_TXCSR,
+                               MUSB_TXCSR_H_WZC_BITS
+                               | MUSB_TXCSR_TXPKTRDY);
+-              goto finish;
++              return;
+       }
+       if (status) {
+@@ -1230,29 +1211,28 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+       /* second cppi case */
+       if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+               DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
+-              goto finish;
+-
++              return;
+       }
+-      /* REVISIT this looks wrong... */
+       if (!status || dma || usb_pipeisoc(pipe)) {
+               if (dma)
+-                      wLength = dma->actual_len;
++                      length = dma->actual_len;
+               else
+-                      wLength = qh->segsize;
+-              qh->offset += wLength;
++                      length = qh->segsize;
++              qh->offset += length;
+               if (usb_pipeisoc(pipe)) {
+                       struct usb_iso_packet_descriptor        *d;
+                       d = urb->iso_frame_desc + qh->iso_idx;
+-                      d->actual_length = qh->segsize;
++                      d->actual_length = length;
++                      d->status = status;
+                       if (++qh->iso_idx >= urb->number_of_packets) {
+                               done = true;
+                       } else {
+                               d++;
+-                              buf = urb->transfer_buffer + d->offset;
+-                              wLength = d->length;
++                              offset = d->offset;
++                              length = d->length;
+                       }
+               } else if (dma) {
+                       done = true;
+@@ -1265,10 +1245,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+                                               & URB_ZERO_PACKET))
+                               done = true;
+                       if (!done) {
+-                              buf = urb->transfer_buffer
+-                                              + qh->offset;
+-                              wLength = urb->transfer_buffer_length
+-                                              - qh->offset;
++                              offset = qh->offset;
++                              length = urb->transfer_buffer_length - offset;
+                       }
+               }
+       }
+@@ -1287,28 +1265,31 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+               urb->status = status;
+               urb->actual_length = qh->offset;
+               musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT);
++              return;
++      } else  if (usb_pipeisoc(pipe) && dma) {
++              if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb,
++                              offset, length))
++                      return;
++      } else  if (tx_csr & MUSB_TXCSR_DMAENAB) {
++              DBG(1, "not complete, but DMA enabled?\n");
++              return;
++      }
+-      } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) {
+-              /* WARN_ON(!buf); */
+-
+-              /* REVISIT:  some docs say that when hw_ep->tx_double_buffered,
+-               * (and presumably, fifo is not half-full) we should write TWO
+-               * packets before updating TXCSR ... other docs disagree ...
+-               */
+-              /* PIO:  start next packet in this URB */
+-              if (wLength > qh->maxpacket)
+-                      wLength = qh->maxpacket;
+-              musb_write_fifo(hw_ep, wLength, buf);
+-              qh->segsize = wLength;
+-
+-              musb_ep_select(mbase, epnum);
+-              musb_writew(epio, MUSB_TXCSR,
+-                              MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
+-      } else
+-              DBG(1, "not complete, but dma enabled?\n");
++      /*
++       * PIO: start next packet in this URB.
++       *
++       * REVISIT: some docs say that when hw_ep->tx_double_buffered,
++       * (and presumably, FIFO is not half-full) we should write *two*
++       * packets before updating TXCSR; other docs disagree...
++       */
++      if (length > qh->maxpacket)
++              length = qh->maxpacket;
++      musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
++      qh->segsize = length;
+-finish:
+-      return;
++      musb_ep_select(mbase, epnum);
++      musb_writew(epio, MUSB_TXCSR,
++                      MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
+ }
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0012-musb-fix-possible-panic-while-resuming.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0012-musb-fix-possible-panic-while-resuming.patch
new file mode 100644 (file)
index 0000000..2bbde84
--- /dev/null
@@ -0,0 +1,56 @@
+From b9a61b80ea89d9d6d78a23d96a28df94fd612298 Mon Sep 17 00:00:00 2001
+From: Kim Kyuwon <q1.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+Date: Thu, 26 Mar 2009 18:56:51 -0700
+Subject: [PATCH] musb: fix possible panic while resuming
+
+During driver resume processing, musb could cause a kernel panic.
+Fix by enabling the clock earlier, with the resume_early method.
+
+Signed-off-by: Kim Kyuwon <q1.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_core.c |    8 ++------
+ 1 files changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index 338cd16..3019725 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -2170,16 +2170,13 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message)
+       return 0;
+ }
+-static int musb_resume(struct platform_device *pdev)
++static int musb_resume_early(struct platform_device *pdev)
+ {
+-      unsigned long   flags;
+       struct musb     *musb = dev_to_musb(&pdev->dev);
+       if (!musb->clock)
+               return 0;
+-      spin_lock_irqsave(&musb->lock, flags);
+-
+       if (musb->set_clock)
+               musb->set_clock(musb->clock, 1);
+       else
+@@ -2189,7 +2186,6 @@ static int musb_resume(struct platform_device *pdev)
+        * unless for some reason the whole soc powered down and we're
+        * not treating that as a whole-system restart (e.g. swsusp)
+        */
+-      spin_unlock_irqrestore(&musb->lock, flags);
+       return 0;
+ }
+@@ -2207,7 +2203,7 @@ static struct platform_driver musb_driver = {
+       .remove         = __devexit_p(musb_remove),
+       .shutdown       = musb_shutdown,
+       .suspend        = musb_suspend,
+-      .resume         = musb_resume,
++      .resume_early   = musb_resume_early,
+ };
+ /*-------------------------------------------------------------------------*/
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch
new file mode 100644 (file)
index 0000000..0202871
--- /dev/null
@@ -0,0 +1,91 @@
+From 2658f7c9029967501cd4d749364f2e02d02eebd5 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:54:21 -0700
+Subject: [PATCH] musb_host: refactor musb_save_toggle() (take 2)
+
+Refactor musb_save_toggle() as follows:
+
+ - replace 'struct musb_hw_ep *ep' parameter by 'struct
+   musb_qh *qh' to avoid re-calculating this value
+
+ - move usb_settogle() call out of the *if* operator.
+
+This is a net minor shrink of source and object code.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |   35 ++++++++++++-----------------------
+ 1 files changed, 12 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index f6e84a0..dc32ce4 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -318,35 +318,24 @@ __acquires(musb->lock)
+       spin_lock(&musb->lock);
+ }
+-/* for bulk/interrupt endpoints only */
+-static inline void
+-musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
++/* For bulk/interrupt endpoints only */
++static inline void musb_save_toggle(struct musb_qh *qh, int is_in,
++                                  struct urb *urb)
+ {
+-      struct usb_device       *udev = urb->dev;
++      void __iomem            *epio = qh->hw_ep->regs;
+       u16                     csr;
+-      void __iomem            *epio = ep->regs;
+-      struct musb_qh          *qh;
+-      /* FIXME:  the current Mentor DMA code seems to have
++      /*
++       * FIXME: the current Mentor DMA code seems to have
+        * problems getting toggle correct.
+        */
+-      if (is_in || ep->is_shared_fifo)
+-              qh = ep->in_qh;
++      if (is_in)
++              csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE;
+       else
+-              qh = ep->out_qh;
++              csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE;
+-      if (!is_in) {
+-              csr = musb_readw(epio, MUSB_TXCSR);
+-              usb_settoggle(udev, qh->epnum, 1,
+-                      (csr & MUSB_TXCSR_H_DATATOGGLE)
+-                              ? 1 : 0);
+-      } else {
+-              csr = musb_readw(epio, MUSB_RXCSR);
+-              usb_settoggle(udev, qh->epnum, 0,
+-                      (csr & MUSB_RXCSR_H_DATATOGGLE)
+-                              ? 1 : 0);
+-      }
++      usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0);
+ }
+ /* caller owns controller lock, irqs are blocked */
+@@ -362,7 +351,7 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_BULK:
+       case USB_ENDPOINT_XFER_INT:
+-              musb_save_toggle(ep, is_in, urb);
++              musb_save_toggle(qh, is_in, urb);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (status == 0 && urb->error_count)
+@@ -1362,7 +1351,7 @@ static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
+                       urb->actual_length += dma->actual_len;
+                       dma->actual_len = 0L;
+               }
+-              musb_save_toggle(ep, 1, urb);
++              musb_save_toggle(cur_qh, 1, urb);
+               /* move cur_qh to end of queue */
+               list_move_tail(&cur_qh->ring, &musb->in_bulk);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch
new file mode 100644 (file)
index 0000000..08e08a8
--- /dev/null
@@ -0,0 +1,32 @@
+From 7766f2ea909b73f56d21746485069e02839b75f1 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:53:32 -0700
+Subject: [PATCH] musb_gadget: suppress "parasitic" TX interrupts with CPPI
+
+Suppress "parasitic" endpoint interrupts in the DMA mode
+when using CPPI DMA driver; they're caused by the MUSB gadget
+driver using the DMA request mode 0 instead of the mode 1.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_gadget.c |    3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index f79440c..bc197b2 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -349,7 +349,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
+ #elif defined(CONFIG_USB_TI_CPPI_DMA)
+               /* program endpoint CSR first, then setup DMA */
+               csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+-              csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
++              csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
++                     MUSB_TXCSR_MODE;
+               musb_writew(epio, MUSB_TXCSR,
+                       (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
+                               | csr);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch
new file mode 100644 (file)
index 0000000..7115b15
--- /dev/null
@@ -0,0 +1,202 @@
+From 5424305125492a2417bde7c6d23ee4b84e25f6be Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:52:43 -0700
+Subject: [PATCH] musb_gadget: fix unhandled endpoint 0 IRQs
+
+The gadget EP0 code routinely ignores an interrupt at end of
+the data phase because of musb_g_ep0_giveback() resetting the
+state machine to "idle, waiting for SETUP" phase prematurely.
+
+The driver also prematurely leaves the status phase on
+receiving the SetupEnd interrupt.
+
+As there were still unhandled endpoint 0 interrupts happening
+from time to time after fixing these issues, there turned to
+be yet another culprit: two distinct gadget states collapsed
+into one.
+
+The (missing) state that comes after STATUS IN/OUT states was
+typically indiscernible from them since the corresponding
+interrupts tend to happen within too little period of time
+(due to only a zero-length status packet in between) and so
+they got coalesced; yet this state is not the same as the next
+one which is associated with the reception of a SETUP packet.
+
+Adding this extra state seems to have fixed the rest of the
+unhandled interrupts that generic_interrupt() and
+davinci_interrupt() hid by faking their result and only
+emitting a debug message -- so, stop doing that.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/davinci.c         |    7 +----
+ drivers/usb/musb/musb_core.c       |    8 +-----
+ drivers/usb/musb/musb_core.h       |    3 +-
+ drivers/usb/musb/musb_gadget_ep0.c |   45 +++++++++++++++++++++++++++++++----
+ 4 files changed, 43 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
+index 2dc7606..399c435 100644
+--- a/drivers/usb/musb/davinci.c
++++ b/drivers/usb/musb/davinci.c
+@@ -357,12 +357,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
+       spin_unlock_irqrestore(&musb->lock, flags);
+-      /* REVISIT we sometimes get unhandled IRQs
+-       * (e.g. ep0).  not clear why...
+-       */
+-      if (retval != IRQ_HANDLED)
+-              DBG(5, "unhandled? %08x\n", tmp);
+-      return IRQ_HANDLED;
++      return retval;
+ }
+ int musb_platform_set_mode(struct musb *musb, u8 mode)
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index 3019725..a1de43b 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -1481,13 +1481,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)
+       spin_unlock_irqrestore(&musb->lock, flags);
+-      /* REVISIT we sometimes get spurious IRQs on g_ep0
+-       * not clear why...
+-       */
+-      if (retval != IRQ_HANDLED)
+-              DBG(5, "spurious?\n");
+-
+-      return IRQ_HANDLED;
++      return retval;
+ }
+ #else
+diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
+index adf1806..f56a56c 100644
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -171,7 +171,8 @@ enum musb_h_ep0_state {
+ /* peripheral side ep0 states */
+ enum musb_g_ep0_state {
+-      MUSB_EP0_STAGE_SETUP,           /* idle, waiting for setup */
++      MUSB_EP0_STAGE_IDLE,            /* idle, waiting for SETUP */
++      MUSB_EP0_STAGE_SETUP,           /* received SETUP */
+       MUSB_EP0_STAGE_TX,              /* IN data */
+       MUSB_EP0_STAGE_RX,              /* OUT data */
+       MUSB_EP0_STAGE_STATUSIN,        /* (after OUT data) */
+diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
+index 3f5e30d..ec0e899 100644
+--- a/drivers/usb/musb/musb_gadget_ep0.c
++++ b/drivers/usb/musb/musb_gadget_ep0.c
+@@ -4,6 +4,7 @@
+  * Copyright 2005 Mentor Graphics Corporation
+  * Copyright (C) 2005-2006 by Texas Instruments
+  * Copyright (C) 2006-2007 Nokia Corporation
++ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source-Igf4POYTYCDQT0dZR+AlfA@public.gmane.org>
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+@@ -58,7 +59,8 @@
+ static char *decode_ep0stage(u8 stage)
+ {
+       switch (stage) {
+-      case MUSB_EP0_STAGE_SETUP:      return "idle";
++      case MUSB_EP0_STAGE_IDLE:       return "idle";
++      case MUSB_EP0_STAGE_SETUP:      return "setup";
+       case MUSB_EP0_STAGE_TX:         return "in";
+       case MUSB_EP0_STAGE_RX:         return "out";
+       case MUSB_EP0_STAGE_ACKWAIT:    return "wait";
+@@ -628,7 +630,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
+               musb_writew(regs, MUSB_CSR0,
+                               csr & ~MUSB_CSR0_P_SENTSTALL);
+               retval = IRQ_HANDLED;
+-              musb->ep0_state = MUSB_EP0_STAGE_SETUP;
++              musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+               csr = musb_readw(regs, MUSB_CSR0);
+       }
+@@ -636,7 +638,18 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
+       if (csr & MUSB_CSR0_P_SETUPEND) {
+               musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
+               retval = IRQ_HANDLED;
+-              musb->ep0_state = MUSB_EP0_STAGE_SETUP;
++              /* Transition into the early status phase */
++              switch (musb->ep0_state) {
++              case MUSB_EP0_STAGE_TX:
++                      musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
++                      break;
++              case MUSB_EP0_STAGE_RX:
++                      musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
++                      break;
++              default:
++                      ERR("SetupEnd came in a wrong ep0stage %s",
++                          decode_ep0stage(musb->ep0_state));
++              }
+               csr = musb_readw(regs, MUSB_CSR0);
+               /* NOTE:  request may need completion */
+       }
+@@ -697,11 +710,31 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
+                       if (req)
+                               musb_g_ep0_giveback(musb, req);
+               }
++
++              /*
++               * In case when several interrupts can get coalesced,
++               * check to see if we've already received a SETUP packet...
++               */
++              if (csr & MUSB_CSR0_RXPKTRDY)
++                      goto setup;
++
++              retval = IRQ_HANDLED;
++              musb->ep0_state = MUSB_EP0_STAGE_IDLE;
++              break;
++
++      case MUSB_EP0_STAGE_IDLE:
++              /*
++               * This state is typically (but not always) indiscernible
++               * from the status states since the corresponding interrupts
++               * tend to happen within too little period of time (with only
++               * a zero-length packet in between) and so get coalesced...
++               */
+               retval = IRQ_HANDLED;
+               musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+               /* FALLTHROUGH */
+       case MUSB_EP0_STAGE_SETUP:
++setup:
+               if (csr & MUSB_CSR0_RXPKTRDY) {
+                       struct usb_ctrlrequest  setup;
+                       int                     handled = 0;
+@@ -783,7 +816,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
+ stall:
+                               DBG(3, "stall (%d)\n", handled);
+                               musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
+-                              musb->ep0_state = MUSB_EP0_STAGE_SETUP;
++                              musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+ finish:
+                               musb_writew(regs, MUSB_CSR0,
+                                               musb->ackpend);
+@@ -803,7 +836,7 @@ finish:
+               /* "can't happen" */
+               WARN_ON(1);
+               musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
+-              musb->ep0_state = MUSB_EP0_STAGE_SETUP;
++              musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+               break;
+       }
+@@ -959,7 +992,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value)
+               csr |= MUSB_CSR0_P_SENDSTALL;
+               musb_writew(regs, MUSB_CSR0, csr);
+-              musb->ep0_state = MUSB_EP0_STAGE_SETUP;
++              musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+               musb->ackpend = 0;
+               break;
+       default:
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch
new file mode 100644 (file)
index 0000000..a2f54ff
--- /dev/null
@@ -0,0 +1,146 @@
+From f9ca8154cf395ec00129f12016697ef610a826ff Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:55:16 -0700
+Subject: [PATCH] musb_host: factor out musb_ep_{get|set}_qh()
+
+Factor out the often used code to get/set the active 'qh'
+pointer for the hardware endpoint.  Change the way the case
+of a shared FIFO is handled by setting *both* 'in_qh' and
+'out_qh' fields of 'struct musb_hw_ep'.  That seems more
+consistent and makes getting to the current 'qh' easy when
+the code knows the direction beforehand.
+
+While at it, turn some assignments into intializers and
+fix declaration style in the vicinity.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |   56 ++++++++++++++++-------------------------
+ 1 files changed, 22 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index dc32ce4..bc89079 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -178,6 +178,19 @@ static inline void cppi_host_txdma_start(struct musb_hw_ep *ep)
+       musb_writew(ep->regs, MUSB_TXCSR, txcsr);
+ }
++static void musb_ep_set_qh(struct musb_hw_ep *ep, int is_in, struct musb_qh *qh)
++{
++      if (is_in != 0 || ep->is_shared_fifo)
++              ep->in_qh  = qh;
++      if (is_in == 0 || ep->is_shared_fifo)
++              ep->out_qh = qh;
++}
++
++static struct musb_qh *musb_ep_get_qh(struct musb_hw_ep *ep, int is_in)
++{
++      return is_in ? ep->in_qh : ep->out_qh;
++}
++
+ /*
+  * Start the URB at the front of an endpoint's queue
+  * end must be claimed from the caller.
+@@ -207,7 +220,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+       case USB_ENDPOINT_XFER_CONTROL:
+               /* control transfers always start with SETUP */
+               is_in = 0;
+-              hw_ep->out_qh = qh;
+               musb->ep0_stage = MUSB_EP0_START;
+               buf = urb->setup_packet;
+               len = 8;
+@@ -236,10 +248,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
+                       epnum, buf + offset, len);
+       /* Configure endpoint */
+-      if (is_in || hw_ep->is_shared_fifo)
+-              hw_ep->in_qh = qh;
+-      else
+-              hw_ep->out_qh = qh;
++      musb_ep_set_qh(hw_ep, is_in, qh);
+       musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len);
+       /* transmit may have more work: start it when it is time */
+@@ -374,11 +383,8 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+               else
+                       ep->tx_reinit = 1;
+-              /* clobber old pointers to this qh */
+-              if (is_in || ep->is_shared_fifo)
+-                      ep->in_qh = NULL;
+-              else
+-                      ep->out_qh = NULL;
++              /* Clobber old pointers to this qh */
++              musb_ep_set_qh(ep, is_in, NULL);
+               qh->hep->hcpriv = NULL;
+               switch (qh->type) {
+@@ -421,12 +427,7 @@ static void
+ musb_advance_schedule(struct musb *musb, struct urb *urb,
+               struct musb_hw_ep *hw_ep, int is_in)
+ {
+-      struct musb_qh  *qh;
+-
+-      if (is_in || hw_ep->is_shared_fifo)
+-              qh = hw_ep->in_qh;
+-      else
+-              qh = hw_ep->out_qh;
++      struct musb_qh          *qh = musb_ep_get_qh(hw_ep, is_in);
+       if (urb->status == -EINPROGRESS)
+               qh = musb_giveback(qh, urb, 0);
+@@ -689,15 +690,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
+       void __iomem            *mbase = musb->mregs;
+       struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
+       void __iomem            *epio = hw_ep->regs;
+-      struct musb_qh          *qh;
+-      u16                     packet_sz;
+-
+-      if (!is_out || hw_ep->is_shared_fifo)
+-              qh = hw_ep->in_qh;
+-      else
+-              qh = hw_ep->out_qh;
+-
+-      packet_sz = qh->maxpacket;
++      struct musb_qh          *qh = musb_ep_get_qh(hw_ep, !is_out);
++      u16                     packet_sz = qh->maxpacket;
+       DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
+                               "h_addr%02x h_port%02x bytes %d\n",
+@@ -1114,17 +1108,14 @@ void musb_host_tx(struct musb *musb, u8 epnum)
+       u16                     tx_csr;
+       size_t                  length = 0;
+       size_t                  offset = 0;
+-      struct urb              *urb;
+       struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
+       void __iomem            *epio = hw_ep->regs;
+-      struct musb_qh          *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh
+-                                                          : hw_ep->out_qh;
++      struct musb_qh          *qh = hw_ep->out_qh;
++      struct urb              *urb = next_urb(qh);
+       u32                     status = 0;
+       void __iomem            *mbase = musb->mregs;
+       struct dma_channel      *dma;
+-      urb = next_urb(qh);
+-
+       musb_ep_select(mbase, epnum);
+       tx_csr = musb_readw(epio, MUSB_TXCSR);
+@@ -1741,10 +1732,7 @@ static int musb_schedule(
+                       epnum++, hw_ep++) {
+               int     diff;
+-              if (is_in || hw_ep->is_shared_fifo) {
+-                      if (hw_ep->in_qh  != NULL)
+-                              continue;
+-              } else  if (hw_ep->out_qh != NULL)
++              if (musb_ep_get_qh(hw_ep, is_in) != NULL)
+                       continue;
+               if (hw_ep == musb->bulk_ep)
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0017-musb_host-refactor-URB-giveback.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0017-musb_host-refactor-URB-giveback.patch
new file mode 100644 (file)
index 0000000..4a520df
--- /dev/null
@@ -0,0 +1,132 @@
+From 013056a09afd324e729d64b9a0e66a004604e1d6 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:58:31 -0700
+Subject: [PATCH] musb_host: refactor URB giveback
+
+As musb_advance_schedule() is now the only remaning
+caller of musb_giveback() (and the only valid context
+of such call), just fold the latter into the former
+and then rename __musb_giveback() into musb_giveback().
+
+This is a net minor shrink.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |   54 +++++++++++++++--------------------------
+ 1 files changed, 20 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index bc89079..e833959 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -292,9 +292,8 @@ start:
+       }
+ }
+-/* caller owns controller lock, irqs are blocked */
+-static void
+-__musb_giveback(struct musb *musb, struct urb *urb, int status)
++/* Context: caller owns controller lock, IRQs are blocked */
++static void musb_giveback(struct musb *musb, struct urb *urb, int status)
+ __releases(musb->lock)
+ __acquires(musb->lock)
+ {
+@@ -347,14 +346,22 @@ static inline void musb_save_toggle(struct musb_qh *qh, int is_in,
+       usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0);
+ }
+-/* caller owns controller lock, irqs are blocked */
+-static struct musb_qh *
+-musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
++/*
++ * Advance this hardware endpoint's queue, completing the specified URB and
++ * advancing to either the next URB queued to that qh, or else invalidating
++ * that qh and advancing to the next qh scheduled after the current one.
++ *
++ * Context: caller owns controller lock, IRQs are blocked
++ */
++static void musb_advance_schedule(struct musb *musb, struct urb *urb,
++                                struct musb_hw_ep *hw_ep, int is_in)
+ {
++      struct musb_qh          *qh = musb_ep_get_qh(hw_ep, is_in);
+       struct musb_hw_ep       *ep = qh->hw_ep;
+-      struct musb             *musb = ep->musb;
+-      int                     is_in = usb_pipein(urb->pipe);
+       int                     ready = qh->is_ready;
++      int                     status;
++
++      status = (urb->status == -EINPROGRESS) ? 0 : urb->status;
+       /* save toggle eagerly, for paranoia */
+       switch (qh->type) {
+@@ -363,13 +370,13 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+               musb_save_toggle(qh, is_in, urb);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+-              if (status == 0 && urb->error_count)
++              if (urb->error_count)
+                       status = -EXDEV;
+               break;
+       }
+       qh->is_ready = 0;
+-      __musb_giveback(musb, urb, status);
++      musb_giveback(musb, urb, status);
+       qh->is_ready = ready;
+       /* reclaim resources (and bandwidth) ASAP; deschedule it, and
+@@ -413,31 +420,10 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+                       break;
+               }
+       }
+-      return qh;
+-}
+-
+-/*
+- * Advance this hardware endpoint's queue, completing the specified urb and
+- * advancing to either the next urb queued to that qh, or else invalidating
+- * that qh and advancing to the next qh scheduled after the current one.
+- *
+- * Context: caller owns controller lock, irqs are blocked
+- */
+-static void
+-musb_advance_schedule(struct musb *musb, struct urb *urb,
+-              struct musb_hw_ep *hw_ep, int is_in)
+-{
+-      struct musb_qh          *qh = musb_ep_get_qh(hw_ep, is_in);
+-
+-      if (urb->status == -EINPROGRESS)
+-              qh = musb_giveback(qh, urb, 0);
+-      else
+-              qh = musb_giveback(qh, urb, urb->status);
+       if (qh != NULL && qh->is_ready) {
+               DBG(4, "... next ep%d %cX urb %p\n",
+-                              hw_ep->epnum, is_in ? 'R' : 'T',
+-                              next_urb(qh));
++                  hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
+               musb_start_urb(musb, is_in, qh);
+       }
+ }
+@@ -2080,7 +2066,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+               ret = 0;
+               qh->is_ready = 0;
+-              __musb_giveback(musb, urb, 0);
++              musb_giveback(musb, urb, 0);
+               qh->is_ready = ready;
+               /* If nothing else (usually musb_giveback) is using it
+@@ -2164,7 +2150,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+                * will activate any of these as it advances.
+                */
+               while (!list_empty(&hep->urb_list))
+-                      __musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
++                      musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
+               hep->hcpriv = NULL;
+               list_del(&qh->ring);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0018-musb-split-out-CPPI-interrupt-handler.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0018-musb-split-out-CPPI-interrupt-handler.patch
new file mode 100644 (file)
index 0000000..bf3d6e7
--- /dev/null
@@ -0,0 +1,167 @@
+From b91b067c531c9322f3719951b07303e790b13475 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:59:46 -0700
+Subject: [PATCH] musb: split out CPPI interrupt handler
+
+As DaVinci DM646x has a dedicated CPPI DMA interrupt, replace
+cppi_completion() (which has always been kind of layering
+violation) by a complete CPPI interrupt handler.
+
+[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: only cppi_dma.c needs platform
+device header, not cppi_dma.h ]
+
+Signed-off-by: Dmitry Krivoschekov <dkrivoschekov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/cppi_dma.c |   34 +++++++++++++++++++++++++++++++---
+ drivers/usb/musb/cppi_dma.h |    6 ++++--
+ drivers/usb/musb/davinci.c  |   14 ++++----------
+ 3 files changed, 39 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
+index ac7227c..6ff3c67 100644
+--- a/drivers/usb/musb/cppi_dma.c
++++ b/drivers/usb/musb/cppi_dma.c
+@@ -6,6 +6,7 @@
+  * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
+  */
++#include <linux/platform_device.h>
+ #include <linux/usb.h>
+ #include "musb_core.h"
+@@ -1145,17 +1146,27 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
+       return completed;
+ }
+-void cppi_completion(struct musb *musb, u32 rx, u32 tx)
++irqreturn_t cppi_interrupt(int irq, void *dev_id)
+ {
+-      void __iomem            *tibase;
+-      int                     i, index;
++      struct musb             *musb = dev_id;
+       struct cppi             *cppi;
++      void __iomem            *tibase;
+       struct musb_hw_ep       *hw_ep = NULL;
++      u32                     rx, tx;
++      int                     i, index;
+       cppi = container_of(musb->dma_controller, struct cppi, controller);
+       tibase = musb->ctrl_base;
++      tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
++      rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
++
++      if (!tx && !rx)
++              return IRQ_NONE;
++
++      DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
++
+       /* process TX channels */
+       for (index = 0; tx; tx = tx >> 1, index++) {
+               struct cppi_channel             *tx_ch;
+@@ -1293,6 +1304,8 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx)
+       /* write to CPPI EOI register to re-enable interrupts */
+       musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
++
++      return IRQ_HANDLED;
+ }
+ /* Instantiate a software object representing a DMA controller. */
+@@ -1300,6 +1313,9 @@ struct dma_controller *__init
+ dma_controller_create(struct musb *musb, void __iomem *mregs)
+ {
+       struct cppi             *controller;
++      struct device           *dev = musb->controller;
++      struct platform_device  *pdev = to_platform_device(dev);
++      int                     irq = platform_get_irq(pdev, 1);
+       controller = kzalloc(sizeof *controller, GFP_KERNEL);
+       if (!controller)
+@@ -1330,6 +1346,15 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
+               return NULL;
+       }
++      if (irq > 0) {
++              if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
++                      dev_err(dev, "request_irq %d failed!\n", irq);
++                      dma_controller_destroy(&controller->controller);
++                      return NULL;
++              }
++              controller->irq = irq;
++      }
++
+       return &controller->controller;
+ }
+@@ -1342,6 +1367,9 @@ void dma_controller_destroy(struct dma_controller *c)
+       cppi = container_of(c, struct cppi, controller);
++      if (cppi->irq)
++              free_irq(cppi->irq, cppi->musb);
++
+       /* assert:  caller stopped the controller first */
+       dma_pool_destroy(cppi->pool);
+diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h
+index 729b407..8a39de3 100644
+--- a/drivers/usb/musb/cppi_dma.h
++++ b/drivers/usb/musb/cppi_dma.h
+@@ -119,6 +119,8 @@ struct cppi {
+       void __iomem                    *mregs;         /* Mentor regs */
+       void __iomem                    *tibase;        /* TI/CPPI regs */
++      int                             irq;
++
+       struct cppi_channel             tx[4];
+       struct cppi_channel             rx[4];
+@@ -127,7 +129,7 @@ struct cppi {
+       struct list_head                tx_complete;
+ };
+-/* irq handling hook */
+-extern void cppi_completion(struct musb *, u32 rx, u32 tx);
++/* CPPI IRQ handler */
++extern irqreturn_t cppi_interrupt(int, void *);
+ #endif                                /* end of ifndef _CPPI_DMA_H_ */
+diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
+index 399c435..9fd74bf 100644
+--- a/drivers/usb/musb/davinci.c
++++ b/drivers/usb/musb/davinci.c
+@@ -250,6 +250,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
+       irqreturn_t     retval = IRQ_NONE;
+       struct musb     *musb = __hci;
+       void __iomem    *tibase = musb->ctrl_base;
++      struct cppi     *cppi;
+       u32             tmp;
+       spin_lock_irqsave(&musb->lock, flags);
+@@ -266,16 +267,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
+       /* CPPI interrupts share the same IRQ line, but have their own
+        * mask, state, "vector", and EOI registers.
+        */
+-      if (is_cppi_enabled()) {
+-              u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
+-              u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
+-
+-              if (cppi_tx || cppi_rx) {
+-                      DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
+-                      cppi_completion(musb, cppi_rx, cppi_tx);
+-                      retval = IRQ_HANDLED;
+-              }
+-      }
++      cppi = container_of(musb->dma_controller, struct cppi, controller);
++      if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
++              retval = cppi_interrupt(irq, __hci);
+       /* ack and handle non-CPPI interrupts */
+       tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0019-musb_host-simplify-check-for-active-URB.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0019-musb_host-simplify-check-for-active-URB.patch
new file mode 100644 (file)
index 0000000..c0e5715
--- /dev/null
@@ -0,0 +1,158 @@
+From 69242ddd26151d45f46011cf7abc581b14699fb2 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:56:26 -0700
+Subject: [PATCH] musb_host: simplify check for active URB
+
+The existance of the scheduling list shouldn't matter in
+determining whether there's currectly an URB executing on a
+hardware endpoint. What should actually matter is the 'in_qh'
+or 'out_qh' fields of the 'struct musb_hw_ep' -- those are
+set in musb_start_urb() and cleared in musb_giveback() when
+the endpoint's URB list drains. Hence we should be able to
+replace the big *switch* statements in musb_urb_dequeue()
+and musb_h_disable() with mere musb_ep_get_qh() calls...
+
+While at it, do some more changes:
+
+ - add 'is_in' variable to musb_urb_dequeue();
+
+ - remove the unnecessary 'epnum' variable from musb_h_disable();
+
+ - fix the comment style in the vicinity.
+
+This is a minor shrink of source and object code.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |   72 ++++++++---------------------------------
+ 1 files changed, 14 insertions(+), 58 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index e833959..e121e0e 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -2008,14 +2008,14 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+ {
+       struct musb             *musb = hcd_to_musb(hcd);
+       struct musb_qh          *qh;
+-      struct list_head        *sched;
+       unsigned long           flags;
++      int                     is_in  = usb_pipein(urb->pipe);
+       int                     ret;
+       DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe),
+-                      usb_pipein(urb->pipe) ? "in" : "out");
++                      is_in ? "in" : "out");
+       spin_lock_irqsave(&musb->lock, flags);
+       ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+@@ -2026,45 +2026,23 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+       if (!qh)
+               goto done;
+-      /* Any URB not actively programmed into endpoint hardware can be
++      /* 
++       * Any URB not actively programmed into endpoint hardware can be
+        * immediately given back; that's any URB not at the head of an
+        * endpoint queue, unless someday we get real DMA queues.  And even
+        * if it's at the head, it might not be known to the hardware...
+        *
+-       * Otherwise abort current transfer, pending dma, etc.; urb->status
++       * Otherwise abort current transfer, pending DMA, etc.; urb->status
+        * has already been updated.  This is a synchronous abort; it'd be
+        * OK to hold off until after some IRQ, though.
++       *
++       * NOTE: qh is invalid unless !list_empty(&hep->urb_list)
+        */
+-      if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
+-              ret = -EINPROGRESS;
+-      else {
+-              switch (qh->type) {
+-              case USB_ENDPOINT_XFER_CONTROL:
+-                      sched = &musb->control;
+-                      break;
+-              case USB_ENDPOINT_XFER_BULK:
+-                      if (qh->mux == 1) {
+-                              if (usb_pipein(urb->pipe))
+-                                      sched = &musb->in_bulk;
+-                              else
+-                                      sched = &musb->out_bulk;
+-                              break;
+-                      }
+-              default:
+-                      /* REVISIT when we get a schedule tree, periodic
+-                       * transfers won't always be at the head of a
+-                       * singleton queue...
+-                       */
+-                      sched = NULL;
+-                      break;
+-              }
+-      }
+-
+-      /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
+-      if (ret < 0 || (sched && qh != first_qh(sched))) {
++      if (!qh->is_ready
++                      || urb->urb_list.prev != &qh->hep->urb_list
++                      || musb_ep_get_qh(qh->hw_ep, is_in) != qh) {
+               int     ready = qh->is_ready;
+-              ret = 0;
+               qh->is_ready = 0;
+               musb_giveback(musb, urb, 0);
+               qh->is_ready = ready;
+@@ -2088,13 +2066,11 @@ done:
+ static void
+ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+ {
+-      u8                      epnum = hep->desc.bEndpointAddress;
++      u8                      is_in = hep->desc.bEndpointAddress & USB_DIR_IN;
+       unsigned long           flags;
+       struct musb             *musb = hcd_to_musb(hcd);
+-      u8                      is_in = epnum & USB_DIR_IN;
+       struct musb_qh          *qh;
+       struct urb              *urb;
+-      struct list_head        *sched;
+       spin_lock_irqsave(&musb->lock, flags);
+@@ -2102,31 +2078,11 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+       if (qh == NULL)
+               goto exit;
+-      switch (qh->type) {
+-      case USB_ENDPOINT_XFER_CONTROL:
+-              sched = &musb->control;
+-              break;
+-      case USB_ENDPOINT_XFER_BULK:
+-              if (qh->mux == 1) {
+-                      if (is_in)
+-                              sched = &musb->in_bulk;
+-                      else
+-                              sched = &musb->out_bulk;
+-                      break;
+-              }
+-      default:
+-              /* REVISIT when we get a schedule tree, periodic transfers
+-               * won't always be at the head of a singleton queue...
+-               */
+-              sched = NULL;
+-              break;
+-      }
+-
+-      /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
++      /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
+-      /* kick first urb off the hardware, if needed */
++      /* Kick the first URB off the hardware, if needed */
+       qh->is_ready = 0;
+-      if (!sched || qh == first_qh(sched)) {
++      if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) {
+               urb = next_urb(qh);
+               /* make software (then hardware) stop ASAP */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch
new file mode 100644 (file)
index 0000000..d89eaad
--- /dev/null
@@ -0,0 +1,58 @@
+From d408894fa4263440ed8a9e68566bacea7e6f6bed Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Date: Fri, 27 Mar 2009 12:57:50 -0700
+Subject: [PATCH] musb_host: streamline musb_cleanup_urb() calls
+
+The argument for the 'is_in' parameter of musb_cleanup_urb()
+is always extracted from an URB that's passed to the function.
+So that parameter is superfluous; remove it.
+
+Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_host.c |    9 +++++----
+ 1 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index e121e0e..71e835e 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -1950,14 +1950,15 @@ done:
+  * called with controller locked, irqs blocked
+  * that hardware queue advances to the next transfer, unless prevented
+  */
+-static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
++static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
+ {
+       struct musb_hw_ep       *ep = qh->hw_ep;
+       void __iomem            *epio = ep->regs;
+       unsigned                hw_end = ep->epnum;
+       void __iomem            *regs = ep->musb->mregs;
+-      u16                     csr;
++      int                     is_in = usb_pipein(urb->pipe);
+       int                     status = 0;
++      u16                     csr;
+       musb_ep_select(regs, hw_end);
+@@ -2056,7 +2057,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+                       kfree(qh);
+               }
+       } else
+-              ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
++              ret = musb_cleanup_urb(urb, qh);
+ done:
+       spin_unlock_irqrestore(&musb->lock, flags);
+       return ret;
+@@ -2090,7 +2091,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
+                       urb->status = -ESHUTDOWN;
+               /* cleanup */
+-              musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
++              musb_cleanup_urb(urb, qh);
+               /* Then nuke all the others ... and advance the
+                * queue on hw_ep (e.g. bulk ring) when we're done.
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch
new file mode 100644 (file)
index 0000000..d9733f9
--- /dev/null
@@ -0,0 +1,70 @@
+From c4804e5a447275553c55bbb0ab1748954cb8fbfc Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Tue, 31 Mar 2009 12:26:10 -0700
+Subject: [PATCH] twl4030-usb: fix minor reporting goofage
+
+Fix a reporting glitch in the twl4030 USB transceiver code.
+It wasn't properly distinguishing the two types of active
+USB link:  ID grounded, vs not.  In the current code that
+distinction doesn't much matter; in the future this bugfix
+should help support better USB controller communications.
+
+Provide a comment sorting out some of the cryptic bits of
+the manual:  different sections use different names for
+key signals, and the register definitions don't help much
+without the explanations and diagrams.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/otg/twl4030-usb.c |   26 +++++++++++++++++++-------
+ 1 files changed, 19 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
+index d9478d0..f740390 100644
+--- a/drivers/usb/otg/twl4030-usb.c
++++ b/drivers/usb/otg/twl4030-usb.c
+@@ -217,6 +217,7 @@
+ /* In module TWL4030_MODULE_PM_MASTER */
+ #define PROTECT_KEY                   0x0E
++#define STS_HW_CONDITIONS             0x0F
+ /* In module TWL4030_MODULE_PM_RECEIVER */
+ #define VUSB_DEDICATED1                       0x7D
+@@ -351,15 +352,26 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
+       int     status;
+       int     linkstat = USB_LINK_UNKNOWN;
+-      /* STS_HW_CONDITIONS */
+-      status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 0x0f);
++      /*
++       * For ID/VBUS sensing, see manual section 15.4.8 ...
++       * except when using only battery backup power, two
++       * comparators produce VBUS_PRES and ID_PRES signals,
++       * which don't match docs elsewhere.  But ... BIT(7)
++       * and BIT(2) of STS_HW_CONDITIONS, respectively, do
++       * seem to match up.  If either is true the USB_PRES
++       * signal is active, the OTG module is activated, and
++       * its interrupt may be raised (may wake the system).
++       */
++      status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER,
++                      STS_HW_CONDITIONS);
+       if (status < 0)
+               dev_err(twl->dev, "USB link status err %d\n", status);
+-      else if (status & BIT(7))
+-              linkstat = USB_LINK_VBUS;
+-      else if (status & BIT(2))
+-              linkstat = USB_LINK_ID;
+-      else
++      else if (status & (BIT(7) | BIT(2))) {
++              if (status & BIT(2))
++                      linkstat = USB_LINK_ID;
++              else
++                      linkstat = USB_LINK_VBUS;
++      } else
+               linkstat = USB_LINK_NONE;
+       dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch
new file mode 100644 (file)
index 0000000..16b5b99
--- /dev/null
@@ -0,0 +1,38 @@
+From ba59a0812ba0e223bd0af8f4dea6c971b6289696 Mon Sep 17 00:00:00 2001
+From: Anand Gadiyar <gadiyar-l0cyMroinI0@public.gmane.org>
+Date: Thu, 2 Apr 2009 12:07:08 -0700
+Subject: [PATCH] musb: use dma mode 1 for TX if transfer size equals maxpacket (v2)
+
+Currently, with Inventra DMA, we use Mode 0 if transfer size is less
+than or equal to the endpoint's maxpacket size.  This requires that
+we explicitly set TXPKTRDY for that transfer.
+
+However the musb_g_tx code will not set TXPKTRDY twice if the last
+transfer is exactly equal to maxpacket, even if request->zero is set.
+Using Mode 1 will solve this; a better fix might be in musb_g_tx().
+
+Without this change, musb will not correctly send out a ZLP if the
+last transfer is the maxpacket size and request->zero is set.
+
+Signed-off-by: Anand Gadiyar <gadiyar-l0cyMroinI0@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_gadget.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index bc197b2..e8f920c 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -310,7 +310,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
+                       /* setup DMA, then program endpoint CSR */
+                       request_size = min(request->length,
+                                               musb_ep->dma->max_len);
+-                      if (request_size <= musb_ep->packet_sz)
++                      if (request_size < musb_ep->packet_sz)
+                               musb_ep->dma->desired_mode = 0;
+                       else
+                               musb_ep->dma->desired_mode = 1;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0023-musb-add-high-bandwidth-ISO-support.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0023-musb-add-high-bandwidth-ISO-support.patch
new file mode 100644 (file)
index 0000000..3038dd1
--- /dev/null
@@ -0,0 +1,187 @@
+From 2e049a88b729ae2fdc0ecdabad1857810bd62737 Mon Sep 17 00:00:00 2001
+From: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
+Date: Fri, 3 Apr 2009 16:16:17 -0700
+Subject: [PATCH] musb: add high bandwidth ISO support
+
+Tested on OMAP3 host side with Creative (Live! Cam Optia) USB camera
+which uses high bandwidth isochronous IN endpoints.  FIFO mode 4 is
+updated to provide the needed 4K endpoint buffer without breaking
+the g_nokia composite gadget configuration.  (This is the only
+gadget driver known to use enough endpoints to notice the change.)
+
+Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_core.c |   19 ++++++++---------
+ drivers/usb/musb/musb_core.h |    3 ++
+ drivers/usb/musb/musb_host.c |   47 +++++++++++++++++++++++++++++++----------
+ drivers/usb/musb/musb_host.h |    1 +
+ 4 files changed, 48 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index a1de43b..d953305 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -1068,14 +1068,13 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
+ { .hw_ep_num =  8, .style = FIFO_RX,   .maxpacket = 512, },
+ { .hw_ep_num =  9, .style = FIFO_TX,   .maxpacket = 512, },
+ { .hw_ep_num =  9, .style = FIFO_RX,   .maxpacket = 512, },
+-{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 512, },
+-{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 512, },
+-{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 512, },
+-{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 512, },
+-{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 512, },
+-{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 512, },
+-{ .hw_ep_num = 13, .style = FIFO_TX,   .maxpacket = 512, },
+-{ .hw_ep_num = 13, .style = FIFO_RX,   .maxpacket = 512, },
++{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 256, },
++{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 64, },
++{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 256, },
++{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 64, },
++{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 256, },
++{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 64, },
++{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, },
+ { .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+ { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+ };
+@@ -1335,11 +1334,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
+       }
+       if (reg & MUSB_CONFIGDATA_HBRXE) {
+               strcat(aInfo, ", HB-ISO Rx");
+-              strcat(aInfo, " (X)");          /* no driver support */
++              musb->hb_iso_rx = true;
+       }
+       if (reg & MUSB_CONFIGDATA_HBTXE) {
+               strcat(aInfo, ", HB-ISO Tx");
+-              strcat(aInfo, " (X)");          /* no driver support */
++              musb->hb_iso_tx = true;
+       }
+       if (reg & MUSB_CONFIGDATA_SOFTCONE)
+               strcat(aInfo, ", SoftConn");
+diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
+index f56a56c..0ac4faf 100644
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -387,6 +387,9 @@ struct musb {
+       unsigned is_multipoint:1;
+       unsigned ignore_disconnect:1;   /* during bus resets */
++      unsigned                hb_iso_rx:1;    /* high bandwidth iso rx? */
++      unsigned                hb_iso_tx:1;    /* high bandwidth iso tx? */
++
+ #ifdef C_MP_TX
+       unsigned bulk_split:1;
+ #define       can_bulk_split(musb,type) \
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index 71e835e..ece5122 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -602,7 +602,8 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
+       musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
+       musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
+       /* NOTE: bulk combining rewrites high bits of maxpacket */
+-      musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket);
++      musb_writew(ep->regs, MUSB_RXMAXP,
++                      qh->maxpacket | ((qh->hb_mult - 1) << 11));
+       ep->rx_reinit = 0;
+ }
+@@ -624,9 +625,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
+       csr = musb_readw(epio, MUSB_TXCSR);
+       if (length > pkt_size) {
+               mode = 1;
+-              csr |= MUSB_TXCSR_AUTOSET
+-                      | MUSB_TXCSR_DMAMODE
+-                      | MUSB_TXCSR_DMAENAB;
++              csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;
++              /* autoset shouldn't be set in high bandwidth */
++              if (qh->hb_mult == 1)
++                      csr |= MUSB_TXCSR_AUTOSET;
+       } else {
+               mode = 0;
+               csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
+@@ -1432,6 +1434,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)
+                       /* packet error reported later */
+                       iso_err = true;
+               }
++      } else if (rx_csr & MUSB_RXCSR_INCOMPRX) {
++              DBG(3, "end %d high bandwidth incomplete ISO packet RX\n",
++                              epnum);
++              status = -EPROTO;
+       }
+       /* faults abort the transfer */
+@@ -1639,7 +1645,11 @@ void musb_host_rx(struct musb *musb, u8 epnum)
+                               val &= ~MUSB_RXCSR_H_AUTOREQ;
+                       else
+                               val |= MUSB_RXCSR_H_AUTOREQ;
+-                      val |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB;
++                      val |= MUSB_RXCSR_DMAENAB;
++
++                      /* autoclear shouldn't be set in high bandwidth */
++                      if (qh->hb_mult == 1)
++                              val |= MUSB_RXCSR_AUTOCLEAR;
+                       musb_writew(epio, MUSB_RXCSR,
+                               MUSB_RXCSR_H_WZC_BITS | val);
+@@ -1725,9 +1735,10 @@ static int musb_schedule(
+                       continue;
+               if (is_in)
+-                      diff = hw_ep->max_packet_sz_rx - qh->maxpacket;
++                      diff = hw_ep->max_packet_sz_rx;
+               else
+-                      diff = hw_ep->max_packet_sz_tx - qh->maxpacket;
++                      diff = hw_ep->max_packet_sz_tx;
++              diff -= (qh->maxpacket * qh->hb_mult);
+               if (diff >= 0 && best_diff > diff) {
+                       best_diff = diff;
+@@ -1830,15 +1841,27 @@ static int musb_urb_enqueue(
+       qh->is_ready = 1;
+       qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
++      qh->type = usb_endpoint_type(epd);
+-      /* no high bandwidth support yet */
+-      if (qh->maxpacket & ~0x7ff) {
+-              ret = -EMSGSIZE;
+-              goto done;
++      /* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
++       * Some musb cores don't support high bandwidth ISO transfers; and
++       * we don't (yet!) support high bandwidth interrupt transfers.
++       */
++      qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03);
++      if (qh->hb_mult > 1) {
++              int ok = (qh->type == USB_ENDPOINT_XFER_ISOC);
++
++              if (ok)
++                      ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx)
++                              || (usb_pipeout(urb->pipe) && musb->hb_iso_tx);
++              if (!ok) {
++                      ret = -EMSGSIZE;
++                      goto done;
++              }
++              qh->maxpacket &= 0x7ff;
+       }
+       qh->epnum = usb_endpoint_num(epd);
+-      qh->type = usb_endpoint_type(epd);
+       /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
+       qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
+diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
+index 0b7fbcd..14b0077 100644
+--- a/drivers/usb/musb/musb_host.h
++++ b/drivers/usb/musb/musb_host.h
+@@ -67,6 +67,7 @@ struct musb_qh {
+       u8                      is_ready;       /* safe to modify hw_ep */
+       u8                      type;           /* XFERTYPE_* */
+       u8                      epnum;
++      u8                      hb_mult;        /* high bandwidth pkts per uf */
+       u16                     maxpacket;
+       u16                     frame;          /* for periodic schedule */
+       unsigned                iso_idx;        /* in urb->iso_frame_desc[] */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0024-USB-otg-adding-nop-usb-transceiver.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0024-USB-otg-adding-nop-usb-transceiver.patch
new file mode 100644 (file)
index 0000000..67004d7
--- /dev/null
@@ -0,0 +1,259 @@
+From de835357b3597af5304742cbd89771d70533292a Mon Sep 17 00:00:00 2001
+From: Ajay Kumar Gupta <ajay.gupta@ti.com>
+Date: Fri, 6 Feb 2009 17:32:35 +0530
+Subject: [PATCH] USB: otg: adding nop usb transceiver
+
+NOP transceiver is used by all the usb transceiver which are mostly
+autonomous and doesn't require any programming or which are built
+into the usb ip itself.NOP transceiver only allocates the memory
+for struct xceiv and calls otg_set_transceiver() so function call
+to otg_get_transceiver() will return a valid transceiver.
+
+NOP transceiver device should be registered by calling
+usb_nop_xceiv_register() from platform files.
+
+Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
+Cc: Felipe Balbi <felipe.balbi@nokia.com>
+Cc: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/otg/Kconfig         |    8 ++
+ drivers/usb/otg/Makefile        |    1 +
+ drivers/usb/otg/nop-usb-xceiv.c |  180 +++++++++++++++++++++++++++++++++++++++
+ include/linux/usb/otg.h         |    4 +
+ 4 files changed, 193 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/usb/otg/nop-usb-xceiv.c
+
+diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
+index 5790a5b..aa884d0 100644
+--- a/drivers/usb/otg/Kconfig
++++ b/drivers/usb/otg/Kconfig
+@@ -51,4 +51,12 @@ config TWL4030_USB
+         This transceiver supports high and full speed devices plus,
+         in host mode, low speed.
++config NOP_USB_XCEIV
++      tristate "NOP USB Transceiver Driver"
++      select USB_OTG_UTILS
++      help
++       this driver is to be used by all the usb transceiver which are either
++       built-in with usb ip or which are autonomous and doesn't require any
++       phy programming such as ISP1x04 etc.
++
+ endif # USB || OTG
+diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
+index d73c7cf..2081678 100644
+--- a/drivers/usb/otg/Makefile
++++ b/drivers/usb/otg/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_OTG_UTILS)    += otg.o
+ obj-$(CONFIG_USB_GPIO_VBUS)   += gpio_vbus.o
+ obj-$(CONFIG_ISP1301_OMAP)    += isp1301_omap.o
+ obj-$(CONFIG_TWL4030_USB)     += twl4030-usb.o
++obj-$(CONFIG_NOP_USB_XCEIV)   += nop-usb-xceiv.o
+ ccflags-$(CONFIG_USB_DEBUG)   += -DDEBUG
+ ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
+diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
+new file mode 100644
+index 0000000..4b933f6
+--- /dev/null
++++ b/drivers/usb/otg/nop-usb-xceiv.c
+@@ -0,0 +1,180 @@
++/*
++ * drivers/usb/otg/nop-usb-xceiv.c
++ *
++ * NOP USB transceiver for all USB transceiver which are either built-in
++ * into USB IP or which are mostly autonomous.
++ *
++ * Copyright (C) 2009 Texas Instruments Inc
++ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Current status:
++ *    this is to add "nop" transceiver for all those phy which is
++ *    autonomous such as isp1504 etc.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/usb/otg.h>
++
++struct nop_usb_xceiv {
++      struct otg_transceiver  otg;
++      struct device           *dev;
++};
++
++static u64 nop_xceiv_dmamask = DMA_32BIT_MASK;
++
++static struct platform_device nop_xceiv_device = {
++      .name           = "nop_usb_xceiv",
++      .id             = -1,
++      .dev = {
++              .dma_mask               = &nop_xceiv_dmamask,
++              .coherent_dma_mask      = DMA_32BIT_MASK,
++              .platform_data          = NULL,
++      },
++};
++
++void usb_nop_xceiv_register(void)
++{
++      if (platform_device_register(&nop_xceiv_device) < 0) {
++              printk(KERN_ERR "Unable to register usb nop transceiver\n");
++              return;
++      }
++}
++
++void usb_nop_xceiv_unregister(void)
++{
++      platform_device_unregister(&nop_xceiv_device);
++}
++
++static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
++{
++      return container_of(x, struct nop_usb_xceiv, otg);
++}
++
++static int nop_set_suspend(struct otg_transceiver *x, int suspend)
++{
++      return 0;
++}
++
++static int nop_set_peripheral(struct otg_transceiver *x,
++              struct usb_gadget *gadget)
++{
++      struct nop_usb_xceiv *nop;
++
++      if (!x)
++              return -ENODEV;
++
++      nop = xceiv_to_nop(x);
++
++      if (!gadget) {
++              nop->otg.gadget = NULL;
++              return -ENODEV;
++      }
++
++      nop->otg.gadget = gadget;
++      nop->otg.state = OTG_STATE_B_IDLE;
++      return 0;
++}
++
++static int nop_set_host(struct otg_transceiver *x, struct usb_bus *host)
++{
++      struct nop_usb_xceiv *nop;
++
++      if (!x)
++              return -ENODEV;
++
++      nop = xceiv_to_nop(x);
++
++      if (!host) {
++              nop->otg.host = NULL;
++              return -ENODEV;
++      }
++
++      nop->otg.host = host;
++      return 0;
++}
++
++static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
++{
++      struct nop_usb_xceiv    *nop;
++      int err;
++
++      nop = kzalloc(sizeof *nop, GFP_KERNEL);
++      if (!nop)
++              return -ENOMEM;
++
++      nop->dev                = &pdev->dev;
++      nop->otg.dev            = nop->dev;
++      nop->otg.label          = "nop-xceiv";
++      nop->otg.state          = OTG_STATE_UNDEFINED;
++      nop->otg.set_host       = nop_set_host;
++      nop->otg.set_peripheral = nop_set_peripheral;
++      nop->otg.set_suspend    = nop_set_suspend;
++
++      err = otg_set_transceiver(&nop->otg);
++      if (err) {
++              dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
++                      err);
++              goto exit;
++      }
++
++      platform_set_drvdata(pdev, nop);
++
++      return 0;
++exit:
++      kfree(nop);
++      return err;
++}
++
++static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev)
++{
++      struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
++
++      otg_set_transceiver(NULL);
++
++      platform_set_drvdata(pdev, NULL);
++      kfree(nop);
++
++      return 0;
++}
++
++static struct platform_driver nop_usb_xceiv_driver = {
++      .probe          = nop_usb_xceiv_probe,
++      .remove         = __devexit_p(nop_usb_xceiv_remove),
++      .driver         = {
++              .name   = "nop_usb_xceiv",
++              .owner  = THIS_MODULE,
++      },
++};
++
++static int __init nop_usb_xceiv_init(void)
++{
++      return platform_driver_register(&nop_usb_xceiv_driver);
++}
++subsys_initcall(nop_usb_xceiv_init);
++
++static void __exit nop_usb_xceiv_exit(void)
++{
++      platform_driver_unregister(&nop_usb_xceiv_driver);
++}
++module_exit(nop_usb_xceiv_exit);
++
++MODULE_ALIAS("platform:nop_usb_xceiv");
++MODULE_AUTHOR("Texas Instruments Inc");
++MODULE_DESCRIPTION("NOP USB Transceiver driver");
++MODULE_LICENSE("GPL");
+diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
+index 94df4fe..54f2424 100644
+--- a/include/linux/usb/otg.h
++++ b/include/linux/usb/otg.h
+@@ -80,6 +80,10 @@ struct otg_transceiver {
+ /* for board-specific init logic */
+ extern int otg_set_transceiver(struct otg_transceiver *);
++#ifdef CONFIG_NOP_USB_XCEIV
++extern void usb_nop_xceiv_register(void);
++extern void usb_nop_xceiv_unregister(void);
++#endif
+ /* for usb host and peripheral controller drivers */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch
new file mode 100644 (file)
index 0000000..21fe7be
--- /dev/null
@@ -0,0 +1,90 @@
+From ae4f027580168814f734cf3c41a662a7f10c744c Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Tue, 31 Mar 2009 12:28:31 -0700
+Subject: [PATCH] nop-usb-xceiv: behave when linked as a module
+
+The NOP OTG transceiver driver needs to be usable from modules.
+Make sure its symbols are always accessible at both compile and
+link time, and make sure the device instance is allocated from
+the heap so that device lifetime rules are obeyed.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/otg/nop-usb-xceiv.c |   25 ++++++++++---------------
+ include/linux/usb/otg.h         |    4 ++--
+ 2 files changed, 12 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
+index 4b933f6..9ed5ea5 100644
+--- a/drivers/usb/otg/nop-usb-xceiv.c
++++ b/drivers/usb/otg/nop-usb-xceiv.c
+@@ -22,8 +22,8 @@
+  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  *
+  * Current status:
+- *    this is to add "nop" transceiver for all those phy which is
+- *    autonomous such as isp1504 etc.
++ *    This provides a "nop" transceiver for PHYs which are
++ *    autonomous such as isp1504, isp1707, etc.
+  */
+ #include <linux/module.h>
+@@ -36,30 +36,25 @@ struct nop_usb_xceiv {
+       struct device           *dev;
+ };
+-static u64 nop_xceiv_dmamask = DMA_32BIT_MASK;
+-
+-static struct platform_device nop_xceiv_device = {
+-      .name           = "nop_usb_xceiv",
+-      .id             = -1,
+-      .dev = {
+-              .dma_mask               = &nop_xceiv_dmamask,
+-              .coherent_dma_mask      = DMA_32BIT_MASK,
+-              .platform_data          = NULL,
+-      },
+-};
++static struct platform_device *pd;
+ void usb_nop_xceiv_register(void)
+ {
+-      if (platform_device_register(&nop_xceiv_device) < 0) {
++      if (pd)
++              return;
++      pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
++      if (!pd) {
+               printk(KERN_ERR "Unable to register usb nop transceiver\n");
+               return;
+       }
+ }
++EXPORT_SYMBOL(usb_nop_xceiv_register);
+ void usb_nop_xceiv_unregister(void)
+ {
+-      platform_device_unregister(&nop_xceiv_device);
++      platform_device_unregister(pd);
+ }
++EXPORT_SYMBOL(usb_nop_xceiv_unregister);
+ static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
+ {
+diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
+index 54f2424..7df8bae 100644
+--- a/include/linux/usb/otg.h
++++ b/include/linux/usb/otg.h
+@@ -80,10 +80,10 @@ struct otg_transceiver {
+ /* for board-specific init logic */
+ extern int otg_set_transceiver(struct otg_transceiver *);
+-#ifdef CONFIG_NOP_USB_XCEIV
++
++/* sometimes transceivers are accessed only through e.g. ULPI */
+ extern void usb_nop_xceiv_register(void);
+ extern void usb_nop_xceiv_unregister(void);
+-#endif
+ /* for usb host and peripheral controller drivers */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch
new file mode 100644 (file)
index 0000000..035a6c7
--- /dev/null
@@ -0,0 +1,1109 @@
+From 43ee46723ffa9dd43d611362064d235440aa04e7 Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Tue, 31 Mar 2009 12:30:04 -0700
+Subject: [PATCH] musb: proper hookup to transceiver drivers
+
+Let the otg_transceiver in MUSB be managed by an external driver;
+don't assume it's integrated.  OMAP3 chips need it to be external,
+and there may be ways to interact with the transceiver which add
+functionality to the system.
+
+Platform init code is responsible for setting up the transeciver,
+probably using the NOP transceiver for integrated transceivers.
+External ones will use whatever the board init code provided,
+such as twl4030 or something more hands-off.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/Kconfig        |    2 +
+ drivers/usb/musb/blackfin.c     |   11 +++-
+ drivers/usb/musb/davinci.c      |   33 +++++++++-----
+ drivers/usb/musb/musb_core.c    |   96 +++++++++++++++++++++------------------
+ drivers/usb/musb/musb_core.h    |    2 +-
+ drivers/usb/musb/musb_gadget.c  |   38 +++++++--------
+ drivers/usb/musb/musb_host.c    |    2 +-
+ drivers/usb/musb/musb_virthub.c |   20 ++++----
+ drivers/usb/musb/omap2430.c     |   62 +++++++++----------------
+ drivers/usb/musb/tusb6010.c     |   70 ++++++++++++++++++-----------
+ 10 files changed, 181 insertions(+), 155 deletions(-)
+
+diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
+index 9985db0..9eea991 100644
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -10,6 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
+ config USB_MUSB_HDRC
+       depends on (USB || USB_GADGET) && HAVE_CLK
+       depends on !SUPERH
++      select NOP_USB_XCEIV if ARCH_DAVINCI
+       select TWL4030_USB if MACH_OMAP_3430SDP
+       select USB_OTG_UTILS
+       tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+@@ -55,6 +56,7 @@ comment "Blackfin high speed USB Support"
+ config USB_TUSB6010
+       boolean "TUSB 6010 support"
+       depends on USB_MUSB_HDRC && !USB_MUSB_SOC
++      select NOP_USB_XCEIV
+       default y
+       help
+         The TUSB 6010 chip, from Texas Instruments, connects a discrete
+diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
+index 7861348..f2f66eb 100644
+--- a/drivers/usb/musb/blackfin.c
++++ b/drivers/usb/musb/blackfin.c
+@@ -143,7 +143,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
+       u16 val;
+       spin_lock_irqsave(&musb->lock, flags);
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_A_IDLE:
+       case OTG_STATE_A_WAIT_BCON:
+               /* Start a new session */
+@@ -154,7 +154,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
+               val = musb_readw(musb->mregs, MUSB_DEVCTL);
+               if (!(val & MUSB_DEVCTL_BDEVICE)) {
+                       gpio_set_value(musb->config->gpio_vrsel, 1);
+-                      musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++                      musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+               } else {
+                       gpio_set_value(musb->config->gpio_vrsel, 0);
+@@ -247,6 +247,11 @@ int __init musb_platform_init(struct musb *musb)
+       }
+       gpio_direction_output(musb->config->gpio_vrsel, 0);
++      usb_nop_xceiv_register();
++      musb->xceiv = otg_get_transceiver();
++      if (!musb->xceiv)
++              return -ENODEV;
++
+       if (ANOMALY_05000346) {
+               bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
+               SSYNC();
+@@ -291,7 +296,7 @@ int __init musb_platform_init(struct musb *musb)
+                       musb_conn_timer_handler, (unsigned long) musb);
+       }
+       if (is_peripheral_enabled(musb))
+-              musb->xceiv.set_power = bfin_set_power;
++              musb->xceiv->set_power = bfin_set_power;
+       musb->isr = blackfin_interrupt;
+diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
+index 9fd74bf..81de742 100644
+--- a/drivers/usb/musb/davinci.c
++++ b/drivers/usb/musb/davinci.c
+@@ -200,7 +200,7 @@ static void otg_timer(unsigned long _musb)
+       DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
+       spin_lock_irqsave(&musb->lock, flags);
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_A_WAIT_VFALL:
+               /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
+                * seems to mis-handle session "start" otherwise (or in our
+@@ -211,7 +211,7 @@ static void otg_timer(unsigned long _musb)
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+                       break;
+               }
+-              musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++              musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+               musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+                       MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
+               break;
+@@ -236,7 +236,7 @@ static void otg_timer(unsigned long _musb)
+               if (devctl & MUSB_DEVCTL_BDEVICE)
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+               else
+-                      musb->xceiv.state = OTG_STATE_A_IDLE;
++                      musb->xceiv->state = OTG_STATE_A_IDLE;
+               break;
+       default:
+               break;
+@@ -310,21 +310,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
+                        * to stop registering in devctl.
+                        */
+                       musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+-                      musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
++                      musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+                       mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+                       WARNING("VBUS error workaround (delay coming)\n");
+               } else if (is_host_enabled(musb) && drvvbus) {
+                       musb->is_active = 1;
+                       MUSB_HST_MODE(musb);
+-                      musb->xceiv.default_a = 1;
+-                      musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++                      musb->xceiv->default_a = 1;
++                      musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+                       portstate(musb->port1_status |= USB_PORT_STAT_POWER);
+                       del_timer(&otg_workaround);
+               } else {
+                       musb->is_active = 0;
+                       MUSB_DEV_MODE(musb);
+-                      musb->xceiv.default_a = 0;
+-                      musb->xceiv.state = OTG_STATE_B_IDLE;
++                      musb->xceiv->default_a = 0;
++                      musb->xceiv->state = OTG_STATE_B_IDLE;
+                       portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+               }
+@@ -346,7 +346,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
+       /* poll for ID change */
+       if (is_otg_enabled(musb)
+-                      && musb->xceiv.state == OTG_STATE_B_IDLE)
++                      && musb->xceiv->state == OTG_STATE_B_IDLE)
+               mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+       spin_unlock_irqrestore(&musb->lock, flags);
+@@ -365,6 +365,11 @@ int __init musb_platform_init(struct musb *musb)
+       void __iomem    *tibase = musb->ctrl_base;
+       u32             revision;
++      usb_nop_xceiv_register();
++      musb->xceiv = otg_get_transceiver();
++      if (!musb->xceiv)
++              return -ENODEV;
++
+       musb->mregs += DAVINCI_BASE_OFFSET;
+       clk_enable(musb->clock);
+@@ -372,7 +377,7 @@ int __init musb_platform_init(struct musb *musb)
+       /* returns zero if e.g. not clocked */
+       revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
+       if (revision == 0)
+-              return -ENODEV;
++              goto fail;
+       if (is_host_enabled(musb))
+               setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+@@ -396,6 +401,10 @@ int __init musb_platform_init(struct musb *musb)
+       musb->isr = davinci_interrupt;
+       return 0;
++
++fail:
++      usb_nop_xceiv_unregister();
++      return -ENODEV;
+ }
+ int musb_platform_exit(struct musb *musb)
+@@ -406,7 +415,7 @@ int musb_platform_exit(struct musb *musb)
+       davinci_source_power(musb, 0 /*off*/, 1);
+       /* delay, to avoid problems with module reload */
+-      if (is_host_enabled(musb) && musb->xceiv.default_a) {
++      if (is_host_enabled(musb) && musb->xceiv->default_a) {
+               int     maxdelay = 30;
+               u8      devctl, warn = 0;
+@@ -435,5 +444,7 @@ int musb_platform_exit(struct musb *musb)
+       clk_disable(musb->clock);
++      usb_nop_xceiv_unregister();
++
+       return 0;
+ }
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index d953305..ac150af 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -267,7 +267,7 @@ void musb_load_testpacket(struct musb *musb)
+ const char *otg_state_string(struct musb *musb)
+ {
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_A_IDLE:          return "a_idle";
+       case OTG_STATE_A_WAIT_VRISE:    return "a_wait_vrise";
+       case OTG_STATE_A_WAIT_BCON:     return "a_wait_bcon";
+@@ -302,11 +302,11 @@ void musb_otg_timer_func(unsigned long data)
+       unsigned long   flags;
+       spin_lock_irqsave(&musb->lock, flags);
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_B_WAIT_ACON:
+               DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n");
+               musb_g_disconnect(musb);
+-              musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++              musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+               musb->is_active = 0;
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+@@ -331,20 +331,20 @@ void musb_hnp_stop(struct musb *musb)
+       void __iomem    *mbase = musb->mregs;
+       u8      reg;
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_A_PERIPHERAL:
+       case OTG_STATE_A_WAIT_VFALL:
+       case OTG_STATE_A_WAIT_BCON:
+               DBG(1, "HNP: Switching back to A-host\n");
+               musb_g_disconnect(musb);
+-              musb->xceiv.state = OTG_STATE_A_IDLE;
++              musb->xceiv->state = OTG_STATE_A_IDLE;
+               MUSB_HST_MODE(musb);
+               musb->is_active = 0;
+               break;
+       case OTG_STATE_B_HOST:
+               DBG(1, "HNP: Disabling HR\n");
+               hcd->self.is_b_host = 0;
+-              musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++              musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+               MUSB_DEV_MODE(musb);
+               reg = musb_readb(mbase, MUSB_POWER);
+               reg |= MUSB_POWER_SUSPENDM;
+@@ -402,7 +402,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+               if (devctl & MUSB_DEVCTL_HM) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+-                      switch (musb->xceiv.state) {
++                      switch (musb->xceiv->state) {
+                       case OTG_STATE_A_SUSPEND:
+                               /* remote wakeup?  later, GetPortStatus
+                                * will stop RESUME signaling
+@@ -425,12 +425,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                               musb->rh_timer = jiffies
+                                               + msecs_to_jiffies(20);
+-                              musb->xceiv.state = OTG_STATE_A_HOST;
++                              musb->xceiv->state = OTG_STATE_A_HOST;
+                               musb->is_active = 1;
+                               usb_hcd_resume_root_hub(musb_to_hcd(musb));
+                               break;
+                       case OTG_STATE_B_WAIT_ACON:
+-                              musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++                              musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+                               musb->is_active = 1;
+                               MUSB_DEV_MODE(musb);
+                               break;
+@@ -441,11 +441,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                       }
+ #endif
+               } else {
+-                      switch (musb->xceiv.state) {
++                      switch (musb->xceiv->state) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       case OTG_STATE_A_SUSPEND:
+                               /* possibly DISCONNECT is upcoming */
+-                              musb->xceiv.state = OTG_STATE_A_HOST;
++                              musb->xceiv->state = OTG_STATE_A_HOST;
+                               usb_hcd_resume_root_hub(musb_to_hcd(musb));
+                               break;
+ #endif
+@@ -490,7 +490,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                */
+               musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+               musb->ep0_stage = MUSB_EP0_START;
+-              musb->xceiv.state = OTG_STATE_A_IDLE;
++              musb->xceiv->state = OTG_STATE_A_IDLE;
+               MUSB_HST_MODE(musb);
+               musb_set_vbus(musb, 1);
+@@ -516,7 +516,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                * REVISIT:  do delays from lots of DEBUG_KERNEL checks
+                * make trouble here, keeping VBUS < 4.4V ?
+                */
+-              switch (musb->xceiv.state) {
++              switch (musb->xceiv->state) {
+               case OTG_STATE_A_HOST:
+                       /* recovery is dicey once we've gotten past the
+                        * initial stages of enumeration, but if VBUS
+@@ -602,11 +602,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+               MUSB_HST_MODE(musb);
+               /* indicate new connection to OTG machine */
+-              switch (musb->xceiv.state) {
++              switch (musb->xceiv->state) {
+               case OTG_STATE_B_PERIPHERAL:
+                       if (int_usb & MUSB_INTR_SUSPEND) {
+                               DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
+-                              musb->xceiv.state = OTG_STATE_B_HOST;
++                              musb->xceiv->state = OTG_STATE_B_HOST;
+                               hcd->self.is_b_host = 1;
+                               int_usb &= ~MUSB_INTR_SUSPEND;
+                       } else
+@@ -614,13 +614,13 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+                       DBG(1, "HNP: Waiting to switch to b_host state\n");
+-                      musb->xceiv.state = OTG_STATE_B_HOST;
++                      musb->xceiv->state = OTG_STATE_B_HOST;
+                       hcd->self.is_b_host = 1;
+                       break;
+               default:
+                       if ((devctl & MUSB_DEVCTL_VBUS)
+                                       == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
+-                              musb->xceiv.state = OTG_STATE_A_HOST;
++                              musb->xceiv->state = OTG_STATE_A_HOST;
+                               hcd->self.is_b_host = 0;
+                       }
+                       break;
+@@ -650,7 +650,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                       }
+               } else if (is_peripheral_capable()) {
+                       DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
+-                      switch (musb->xceiv.state) {
++                      switch (musb->xceiv->state) {
+ #ifdef CONFIG_USB_OTG
+                       case OTG_STATE_A_SUSPEND:
+                               /* We need to ignore disconnect on suspend
+@@ -673,12 +673,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                       case OTG_STATE_B_WAIT_ACON:
+                               DBG(1, "HNP: RESET (%s), to b_peripheral\n",
+                                       otg_state_string(musb));
+-                              musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++                              musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+                               musb_g_reset(musb);
+                               break;
+ #endif
+                       case OTG_STATE_B_IDLE:
+-                              musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++                              musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+                               /* FALLTHROUGH */
+                       case OTG_STATE_B_PERIPHERAL:
+                               musb_g_reset(musb);
+@@ -763,7 +763,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+                               MUSB_MODE(musb), devctl);
+               handled = IRQ_HANDLED;
+-              switch (musb->xceiv.state) {
++              switch (musb->xceiv->state) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+               case OTG_STATE_A_HOST:
+               case OTG_STATE_A_SUSPEND:
+@@ -805,7 +805,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+                               otg_state_string(musb), devctl, power);
+               handled = IRQ_HANDLED;
+-              switch (musb->xceiv.state) {
++              switch (musb->xceiv->state) {
+ #ifdef        CONFIG_USB_MUSB_OTG
+               case OTG_STATE_A_PERIPHERAL:
+                       /*
+@@ -817,10 +817,10 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_suspend(musb);
+                       musb->is_active = is_otg_enabled(musb)
+-                                      && musb->xceiv.gadget->b_hnp_enable;
++                                      && musb->xceiv->gadget->b_hnp_enable;
+                       if (musb->is_active) {
+ #ifdef        CONFIG_USB_MUSB_OTG
+-                              musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
++                              musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+                               DBG(1, "HNP: Setting timer for b_ase0_brst\n");
+                               musb_otg_timer.data = (unsigned long)musb;
+                               mod_timer(&musb_otg_timer, jiffies
+@@ -834,9 +834,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+                                       + msecs_to_jiffies(musb->a_wait_bcon));
+                       break;
+               case OTG_STATE_A_HOST:
+-                      musb->xceiv.state = OTG_STATE_A_SUSPEND;
++                      musb->xceiv->state = OTG_STATE_A_SUSPEND;
+                       musb->is_active = is_otg_enabled(musb)
+-                                      && musb->xceiv.host->b_hnp_enable;
++                                      && musb->xceiv->host->b_hnp_enable;
+                       break;
+               case OTG_STATE_B_HOST:
+                       /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+@@ -1681,7 +1681,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
+       spin_lock_irqsave(&musb->lock, flags);
+       musb->a_wait_bcon = val;
+-      if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
++      if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
+               musb->is_active = 0;
+       musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
+       spin_unlock_irqrestore(&musb->lock, flags);
+@@ -1742,8 +1742,8 @@ static void musb_irq_work(struct work_struct *data)
+       struct musb *musb = container_of(data, struct musb, irq_work);
+       static int old_state;
+-      if (musb->xceiv.state != old_state) {
+-              old_state = musb->xceiv.state;
++      if (musb->xceiv->state != old_state) {
++              old_state = musb->xceiv->state;
+               sysfs_notify(&musb->controller->kobj, NULL, "mode");
+       }
+ }
+@@ -1840,7 +1840,7 @@ static void musb_free(struct musb *musb)
+       }
+ #ifdef CONFIG_USB_MUSB_OTG
+-      put_device(musb->xceiv.dev);
++      put_device(musb->xceiv->dev);
+ #endif
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+@@ -1921,10 +1921,18 @@ bad_config:
+               }
+       }
+-      /* assume vbus is off */
+-
+-      /* platform adjusts musb->mregs and musb->isr if needed,
+-       * and activates clocks
++      /* The musb_platform_init() call:
++       *   - adjusts musb->mregs and musb->isr if needed,
++       *   - may initialize an integrated tranceiver
++       *   - initializes musb->xceiv, usually by otg_get_transceiver()
++       *   - activates clocks.
++       *   - stops powering VBUS
++       *   - assigns musb->board_set_vbus if host mode is enabled
++       *
++       * There are various transciever configurations.  Blackfin,
++       * DaVinci, TUSB60x0, and others integrate them.  OMAP3 uses
++       * external/discrete ones in various flavors (twl4030 family,
++       * isp1504, non-OTG, etc) mostly hooking up through ULPI.
+        */
+       musb->isr = generic_interrupt;
+       status = musb_platform_init(musb);
+@@ -1992,17 +2000,17 @@ bad_config:
+                               ? "DMA" : "PIO",
+                       musb->nIrq);
+-#ifdef CONFIG_USB_MUSB_HDRC_HCD
+-      /* host side needs more setup, except for no-host modes */
+-      if (musb->board_mode != MUSB_PERIPHERAL) {
++      /* host side needs more setup */
++      if (is_host_enabled(musb)) {
+               struct usb_hcd  *hcd = musb_to_hcd(musb);
+-              if (musb->board_mode == MUSB_OTG)
++              otg_set_host(musb->xceiv, &hcd->self);
++
++              if (is_otg_enabled(musb))
+                       hcd->self.otg_port = 1;
+-              musb->xceiv.host = &hcd->self;
++              musb->xceiv->host = &hcd->self;
+               hcd->power_budget = 2 * (plat->power ? : 250);
+       }
+-#endif                                /* CONFIG_USB_MUSB_HDRC_HCD */
+       /* For the host-only role, we can activate right away.
+        * (We expect the ID pin to be forcibly grounded!!)
+@@ -2010,8 +2018,8 @@ bad_config:
+        */
+       if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+               MUSB_HST_MODE(musb);
+-              musb->xceiv.default_a = 1;
+-              musb->xceiv.state = OTG_STATE_A_IDLE;
++              musb->xceiv->default_a = 1;
++              musb->xceiv->state = OTG_STATE_A_IDLE;
+               status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+               if (status)
+@@ -2026,8 +2034,8 @@ bad_config:
+       } else /* peripheral is enabled */ {
+               MUSB_DEV_MODE(musb);
+-              musb->xceiv.default_a = 0;
+-              musb->xceiv.state = OTG_STATE_B_IDLE;
++              musb->xceiv->default_a = 0;
++              musb->xceiv->state = OTG_STATE_B_IDLE;
+               status = musb_gadget_setup(musb);
+               if (status)
+diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
+index 0ac4faf..c3ee348 100644
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -356,7 +356,7 @@ struct musb {
+       u16                     int_rx;
+       u16                     int_tx;
+-      struct otg_transceiver  xceiv;
++      struct otg_transceiver  *xceiv;
+       int nIrq;
+       unsigned                irq_wake:1;
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index e8f920c..2fbfba5 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -1406,7 +1406,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
+       spin_lock_irqsave(&musb->lock, flags);
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_B_PERIPHERAL:
+               /* NOTE:  OTG state machine doesn't include B_SUSPENDED;
+                * that's part of the standard usb 1.1 state machine, and
+@@ -1508,9 +1508,9 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+ {
+       struct musb     *musb = gadget_to_musb(gadget);
+-      if (!musb->xceiv.set_power)
++      if (!musb->xceiv->set_power)
+               return -EOPNOTSUPP;
+-      return otg_set_power(&musb->xceiv, mA);
++      return otg_set_power(musb->xceiv, mA);
+ }
+ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
+@@ -1733,11 +1733,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+               spin_lock_irqsave(&musb->lock, flags);
+-              /* REVISIT always use otg_set_peripheral(), handling
+-               * issues including the root hub one below ...
+-               */
+-              musb->xceiv.gadget = &musb->g;
+-              musb->xceiv.state = OTG_STATE_B_IDLE;
++              otg_set_peripheral(musb->xceiv, &musb->g);
+               musb->is_active = 1;
+               /* FIXME this ignores the softconnect flag.  Drivers are
+@@ -1749,6 +1745,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+               if (!is_otg_enabled(musb))
+                       musb_start(musb);
++              otg_set_peripheral(musb->xceiv, &musb->g);
++
+               spin_unlock_irqrestore(&musb->lock, flags);
+               if (is_otg_enabled(musb)) {
+@@ -1762,8 +1760,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+                       if (retval < 0) {
+                               DBG(1, "add_hcd failed, %d\n", retval);
+                               spin_lock_irqsave(&musb->lock, flags);
+-                              musb->xceiv.gadget = NULL;
+-                              musb->xceiv.state = OTG_STATE_UNDEFINED;
++                              otg_set_peripheral(musb->xceiv, NULL);
+                               musb->gadget_driver = NULL;
+                               musb->g.dev.driver = NULL;
+                               spin_unlock_irqrestore(&musb->lock, flags);
+@@ -1846,8 +1843,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+               (void) musb_gadget_vbus_draw(&musb->g, 0);
+-              musb->xceiv.state = OTG_STATE_UNDEFINED;
++              musb->xceiv->state = OTG_STATE_UNDEFINED;
+               stop_activity(musb, driver);
++              otg_set_peripheral(musb->xceiv, NULL);
+               DBG(3, "unregistering driver %s\n", driver->function);
+               spin_unlock_irqrestore(&musb->lock, flags);
+@@ -1883,7 +1881,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
+ void musb_g_resume(struct musb *musb)
+ {
+       musb->is_suspended = 0;
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_B_IDLE:
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+@@ -1909,10 +1907,10 @@ void musb_g_suspend(struct musb *musb)
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+       DBG(3, "devctl %02x\n", devctl);
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_B_IDLE:
+               if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+-                      musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++                      musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               musb->is_suspended = 1;
+@@ -1958,22 +1956,22 @@ void musb_g_disconnect(struct musb *musb)
+               spin_lock(&musb->lock);
+       }
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       default:
+ #ifdef        CONFIG_USB_MUSB_OTG
+               DBG(2, "Unhandled disconnect %s, setting a_idle\n",
+                       otg_state_string(musb));
+-              musb->xceiv.state = OTG_STATE_A_IDLE;
++              musb->xceiv->state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+-              musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
++              musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_HOST:
+ #endif
+       case OTG_STATE_B_PERIPHERAL:
+       case OTG_STATE_B_IDLE:
+-              musb->xceiv.state = OTG_STATE_B_IDLE;
++              musb->xceiv->state = OTG_STATE_B_IDLE;
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               break;
+@@ -2029,10 +2027,10 @@ __acquires(musb->lock)
+        * or else after HNP, as A-Device
+        */
+       if (devctl & MUSB_DEVCTL_BDEVICE) {
+-              musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++              musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+               musb->g.is_a_peripheral = 0;
+       } else if (is_otg_enabled(musb)) {
+-              musb->xceiv.state = OTG_STATE_A_PERIPHERAL;
++              musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
+               musb->g.is_a_peripheral = 1;
+       } else
+               WARN_ON(1);
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index ece5122..795dabe 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -2169,7 +2169,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
+ {
+       struct musb     *musb = hcd_to_musb(hcd);
+-      if (musb->xceiv.state == OTG_STATE_A_SUSPEND)
++      if (musb->xceiv->state == OTG_STATE_A_SUSPEND)
+               return 0;
+       if (is_host_active(musb) && musb->is_active) {
+diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
+index e0e9ce5..7e7900f 100644
+--- a/drivers/usb/musb/musb_virthub.c
++++ b/drivers/usb/musb/musb_virthub.c
+@@ -78,18 +78,18 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
+               DBG(3, "Root port suspended, power %02x\n", power);
+               musb->port1_status |= USB_PORT_STAT_SUSPEND;
+-              switch (musb->xceiv.state) {
++              switch (musb->xceiv->state) {
+               case OTG_STATE_A_HOST:
+-                      musb->xceiv.state = OTG_STATE_A_SUSPEND;
++                      musb->xceiv->state = OTG_STATE_A_SUSPEND;
+                       musb->is_active = is_otg_enabled(musb)
+-                                      && musb->xceiv.host->b_hnp_enable;
++                                      && musb->xceiv->host->b_hnp_enable;
+                       musb_platform_try_idle(musb, 0);
+                       break;
+ #ifdef        CONFIG_USB_MUSB_OTG
+               case OTG_STATE_B_HOST:
+-                      musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
++                      musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+                       musb->is_active = is_otg_enabled(musb)
+-                                      && musb->xceiv.host->b_hnp_enable;
++                                      && musb->xceiv->host->b_hnp_enable;
+                       musb_platform_try_idle(musb, 0);
+                       break;
+ #endif
+@@ -116,7 +116,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
+       void __iomem    *mbase = musb->mregs;
+ #ifdef CONFIG_USB_MUSB_OTG
+-      if (musb->xceiv.state == OTG_STATE_B_IDLE) {
++      if (musb->xceiv->state == OTG_STATE_B_IDLE) {
+               DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n");
+               musb->port1_status &= ~USB_PORT_STAT_RESET;
+               return;
+@@ -186,14 +186,14 @@ void musb_root_disconnect(struct musb *musb)
+       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+       musb->is_active = 0;
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_SUSPEND:
+-              musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++              musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+               musb->is_active = 0;
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+-              musb->xceiv.state = OTG_STATE_B_IDLE;
++              musb->xceiv->state = OTG_STATE_B_IDLE;
+               break;
+       default:
+               DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
+@@ -332,7 +332,7 @@ int musb_hub_control(
+                       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+                       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+                       /* NOTE: it might really be A_WAIT_BCON ... */
+-                      musb->xceiv.state = OTG_STATE_A_HOST;
++                      musb->xceiv->state = OTG_STATE_A_HOST;
+               }
+               put_unaligned(cpu_to_le32(musb->port1_status
+diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
+index 901dffd..5f67b03 100644
+--- a/drivers/usb/musb/omap2430.c
++++ b/drivers/usb/musb/omap2430.c
+@@ -62,17 +62,17 @@ static void musb_do_idle(unsigned long _musb)
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_A_WAIT_BCON:
+               devctl &= ~MUSB_DEVCTL_SESSION;
+               musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               if (devctl & MUSB_DEVCTL_BDEVICE) {
+-                      musb->xceiv.state = OTG_STATE_B_IDLE;
++                      musb->xceiv->state = OTG_STATE_B_IDLE;
+                       MUSB_DEV_MODE(musb);
+               } else {
+-                      musb->xceiv.state = OTG_STATE_A_IDLE;
++                      musb->xceiv->state = OTG_STATE_A_IDLE;
+                       MUSB_HST_MODE(musb);
+               }
+               break;
+@@ -90,7 +90,7 @@ static void musb_do_idle(unsigned long _musb)
+                       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+                       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+                       /* NOTE: it might really be A_WAIT_BCON ... */
+-                      musb->xceiv.state = OTG_STATE_A_HOST;
++                      musb->xceiv->state = OTG_STATE_A_HOST;
+               }
+               break;
+ #endif
+@@ -98,9 +98,9 @@ static void musb_do_idle(unsigned long _musb)
+       case OTG_STATE_A_HOST:
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               if (devctl &  MUSB_DEVCTL_BDEVICE)
+-                      musb->xceiv.state = OTG_STATE_B_IDLE;
++                      musb->xceiv->state = OTG_STATE_B_IDLE;
+               else
+-                      musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++                      musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ #endif
+       default:
+               break;
+@@ -119,7 +119,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+       /* Never idle if active, or when VBUS timeout is not set as host */
+       if (musb->is_active || ((musb->a_wait_bcon == 0)
+-                      && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
++                      && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
+               DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+               del_timer(&musb_idle_timer);
+               last_timer = jiffies;
+@@ -164,8 +164,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
+       if (is_on) {
+               musb->is_active = 1;
+-              musb->xceiv.default_a = 1;
+-              musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++              musb->xceiv->default_a = 1;
++              musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+               devctl |= MUSB_DEVCTL_SESSION;
+               MUSB_HST_MODE(musb);
+@@ -176,8 +176,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
+                * jumping right to B_IDLE...
+                */
+-              musb->xceiv.default_a = 0;
+-              musb->xceiv.state = OTG_STATE_B_IDLE;
++              musb->xceiv->default_a = 0;
++              musb->xceiv->state = OTG_STATE_B_IDLE;
+               devctl &= ~MUSB_DEVCTL_SESSION;
+               MUSB_DEV_MODE(musb);
+@@ -189,10 +189,6 @@ static void omap_set_vbus(struct musb *musb, int is_on)
+               otg_state_string(musb),
+               musb_readb(musb->mregs, MUSB_DEVCTL));
+ }
+-static int omap_set_power(struct otg_transceiver *x, unsigned mA)
+-{
+-      return 0;
+-}
+ static int musb_platform_resume(struct musb *musb);
+@@ -203,24 +199,6 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+       devctl |= MUSB_DEVCTL_SESSION;
+       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+-      switch (musb_mode) {
+-#ifdef CONFIG_USB_MUSB_HDRC_HCD
+-      case MUSB_HOST:
+-              otg_set_host(&musb->xceiv, musb->xceiv.host);
+-              break;
+-#endif
+-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+-      case MUSB_PERIPHERAL:
+-              otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
+-              break;
+-#endif
+-#ifdef CONFIG_USB_MUSB_OTG
+-      case MUSB_OTG:
+-              break;
+-#endif
+-      default:
+-              return -EINVAL;
+-      }
+       return 0;
+ }
+@@ -232,6 +210,16 @@ int __init musb_platform_init(struct musb *musb)
+       omap_cfg_reg(AE5_2430_USB0HS_STP);
+ #endif
++      /* We require some kind of external transceiver, hooked
++       * up through ULPI.  TWL4030-family PMICs include one,
++       * which needs a driver, drivers aren't always needed.
++       */
++      musb->xceiv = otg_get_transceiver();
++      if (!musb->xceiv) {
++              pr_err("HS USB OTG: no transceiver configured\n");
++              return -ENODEV;
++      }
++
+       musb_platform_resume(musb);
+       l = omap_readl(OTG_SYSCONFIG);
+@@ -258,8 +246,6 @@ int __init musb_platform_init(struct musb *musb)
+       if (is_host_enabled(musb))
+               musb->board_set_vbus = omap_set_vbus;
+-      if (is_peripheral_enabled(musb))
+-              musb->xceiv.set_power = omap_set_power;
+       musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
+       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+@@ -283,8 +269,7 @@ int musb_platform_suspend(struct musb *musb)
+       l |= ENABLEWAKEUP;      /* enable wakeup */
+       omap_writel(l, OTG_SYSCONFIG);
+-      if (musb->xceiv.set_suspend)
+-              musb->xceiv.set_suspend(&musb->xceiv, 1);
++      otg_set_suspend(musb->xceiv, 1);
+       if (musb->set_clock)
+               musb->set_clock(musb->clock, 0);
+@@ -301,8 +286,7 @@ static int musb_platform_resume(struct musb *musb)
+       if (!musb->clock)
+               return 0;
+-      if (musb->xceiv.set_suspend)
+-              musb->xceiv.set_suspend(&musb->xceiv, 0);
++      otg_set_suspend(musb->xceiv, 0);
+       if (musb->set_clock)
+               musb->set_clock(musb->clock, 1);
+diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
+index 9e20fd0..c473dec 100644
+--- a/drivers/usb/musb/tusb6010.c
++++ b/drivers/usb/musb/tusb6010.c
+@@ -260,6 +260,8 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+               tusb_fifo_read_unaligned(fifo, buf, len);
+ }
++static struct musb *the_musb;
++
+ #ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ /* This is used by gadget drivers, and OTG transceiver logic, allowing
+@@ -270,7 +272,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+  */
+ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
+ {
+-      struct musb     *musb = container_of(x, struct musb, xceiv);
++      struct musb     *musb = the_musb;
+       void __iomem    *tbase = musb->ctrl_base;
+       u32             reg;
+@@ -420,7 +422,7 @@ static void musb_do_idle(unsigned long _musb)
+       spin_lock_irqsave(&musb->lock, flags);
+-      switch (musb->xceiv.state) {
++      switch (musb->xceiv->state) {
+       case OTG_STATE_A_WAIT_BCON:
+               if ((musb->a_wait_bcon != 0)
+                       && (musb->idle_timeout == 0
+@@ -484,7 +486,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+       /* Never idle if active, or when VBUS timeout is not set as host */
+       if (musb->is_active || ((musb->a_wait_bcon == 0)
+-                      && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
++                      && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
+               DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+               del_timer(&musb_idle_timer);
+               last_timer = jiffies;
+@@ -533,8 +535,8 @@ static void tusb_source_power(struct musb *musb, int is_on)
+               if (musb->set_clock)
+                       musb->set_clock(musb->clock, 1);
+               timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
+-              musb->xceiv.default_a = 1;
+-              musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++              musb->xceiv->default_a = 1;
++              musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+               devctl |= MUSB_DEVCTL_SESSION;
+               conf |= TUSB_DEV_CONF_USB_HOST_MODE;
+@@ -547,24 +549,24 @@ static void tusb_source_power(struct musb *musb, int is_on)
+               /* If ID pin is grounded, we want to be a_idle */
+               otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+               if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
+-                      switch (musb->xceiv.state) {
++                      switch (musb->xceiv->state) {
+                       case OTG_STATE_A_WAIT_VRISE:
+                       case OTG_STATE_A_WAIT_BCON:
+-                              musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
++                              musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+                               break;
+                       case OTG_STATE_A_WAIT_VFALL:
+-                              musb->xceiv.state = OTG_STATE_A_IDLE;
++                              musb->xceiv->state = OTG_STATE_A_IDLE;
+                               break;
+                       default:
+-                              musb->xceiv.state = OTG_STATE_A_IDLE;
++                              musb->xceiv->state = OTG_STATE_A_IDLE;
+                       }
+                       musb->is_active = 0;
+-                      musb->xceiv.default_a = 1;
++                      musb->xceiv->default_a = 1;
+                       MUSB_HST_MODE(musb);
+               } else {
+                       musb->is_active = 0;
+-                      musb->xceiv.default_a = 0;
+-                      musb->xceiv.state = OTG_STATE_B_IDLE;
++                      musb->xceiv->default_a = 0;
++                      musb->xceiv->state = OTG_STATE_B_IDLE;
+                       MUSB_DEV_MODE(musb);
+               }
+@@ -675,7 +677,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+               else
+                       default_a = is_host_enabled(musb);
+               DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
+-              musb->xceiv.default_a = default_a;
++              musb->xceiv->default_a = default_a;
+               tusb_source_power(musb, default_a);
+               /* Don't allow idling immediately */
+@@ -687,7 +689,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+       if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
+               /* B-dev state machine:  no vbus ~= disconnect */
+-              if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
++              if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
+                               || !is_host_enabled(musb)) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       /* ? musb_root_disconnect(musb); */
+@@ -702,9 +704,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+                       if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
+                               DBG(1, "Forcing disconnect (no interrupt)\n");
+-                              if (musb->xceiv.state != OTG_STATE_B_IDLE) {
++                              if (musb->xceiv->state != OTG_STATE_B_IDLE) {
+                                       /* INTR_DISCONNECT can hide... */
+-                                      musb->xceiv.state = OTG_STATE_B_IDLE;
++                                      musb->xceiv->state = OTG_STATE_B_IDLE;
+                                       musb->int_usb |= MUSB_INTR_DISCONNECT;
+                               }
+                               musb->is_active = 0;
+@@ -718,7 +720,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+                       DBG(2, "vbus change, %s, otg %03x\n",
+                               otg_state_string(musb), otg_stat);
+-                      switch (musb->xceiv.state) {
++                      switch (musb->xceiv->state) {
+                       case OTG_STATE_A_IDLE:
+                               DBG(2, "Got SRP, turning on VBUS\n");
+                               musb_set_vbus(musb, 1);
+@@ -766,7 +768,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+               DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
+-              switch (musb->xceiv.state) {
++              switch (musb->xceiv->state) {
+               case OTG_STATE_A_WAIT_VRISE:
+                       /* VBUS has probably been valid for a while now,
+                        * but may well have bounced out of range a bit
+@@ -778,7 +780,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+                                       DBG(2, "devctl %02x\n", devctl);
+                                       break;
+                               }
+-                              musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++                              musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+                               musb->is_active = 0;
+                               idle_timeout = jiffies
+                                       + msecs_to_jiffies(musb->a_wait_bcon);
+@@ -1094,9 +1096,14 @@ int __init musb_platform_init(struct musb *musb)
+ {
+       struct platform_device  *pdev;
+       struct resource         *mem;
+-      void __iomem            *sync;
++      void __iomem            *sync = NULL;
+       int                     ret;
++      usb_nop_xceiv_register();
++      musb->xceiv = otg_get_transceiver();
++      if (!musb->xceiv)
++              return -ENODEV;
++
+       pdev = to_platform_device(musb->controller);
+       /* dma address for async dma */
+@@ -1107,14 +1114,16 @@ int __init musb_platform_init(struct musb *musb)
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!mem) {
+               pr_debug("no sync dma resource?\n");
+-              return -ENODEV;
++              ret = -ENODEV;
++              goto done;
+       }
+       musb->sync = mem->start;
+       sync = ioremap(mem->start, mem->end - mem->start + 1);
+       if (!sync) {
+               pr_debug("ioremap for sync failed\n");
+-              return -ENOMEM;
++              ret = -ENOMEM;
++              goto done;
+       }
+       musb->sync_va = sync;
+@@ -1127,28 +1136,37 @@ int __init musb_platform_init(struct musb *musb)
+       if (ret) {
+               printk(KERN_ERR "Could not start tusb6010 (%d)\n",
+                               ret);
+-              return -ENODEV;
++              goto done;
+       }
+       musb->isr = tusb_interrupt;
+       if (is_host_enabled(musb))
+               musb->board_set_vbus = tusb_source_power;
+-      if (is_peripheral_enabled(musb))
+-              musb->xceiv.set_power = tusb_draw_power;
++      if (is_peripheral_enabled(musb)) {
++              musb->xceiv->set_power = tusb_draw_power;
++              the_musb = musb;
++      }
+       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
++done:
++      if (ret < 0) {
++              if (sync)
++                      iounmap(sync);
++              usb_nop_xceiv_unregister();
++      }
+       return ret;
+ }
+ int musb_platform_exit(struct musb *musb)
+ {
+       del_timer_sync(&musb_idle_timer);
++      the_musb = NULL;
+       if (musb->board_set_power)
+               musb->board_set_power(0);
+       iounmap(musb->sync_va);
+-
++      usb_nop_xceiv_unregister();
+       return 0;
+ }
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0027-musb-otg-timer-cleanup.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0027-musb-otg-timer-cleanup.patch
new file mode 100644 (file)
index 0000000..f41b766
--- /dev/null
@@ -0,0 +1,198 @@
+From b4b8c1e7604784b9877f07400ff2a718118ef05c Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Tue, 31 Mar 2009 12:32:12 -0700
+Subject: [PATCH] musb: otg timer cleanup
+
+Minor cleanup of OTG timer handling:
+    * unify decls for OTG time constants, in the core header
+    * set up and use that timer in a more normal way
+    * move to the driver struct, so it's usable outside core
+
+And tighten use and setup of T(a_wait_bcon) so that if it's used,
+it's always valid.  (If that timer expires, the A-device will
+stop powering VBUS.  For non-OTG systems, that will be a surprise.)
+No behavioral changes, other than more consistency when applying
+that core HNP timeout.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_core.c |   41 ++++++++++++++++++++++-------------------
+ drivers/usb/musb/musb_core.h |   14 +++++++++++---
+ drivers/usb/musb/omap2430.c  |    2 --
+ 3 files changed, 33 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index ac150af..05c5dd3 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -112,6 +112,7 @@
+ #include "davinci.h"
+ #endif
++#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
+ unsigned musb_debug;
+@@ -288,12 +289,6 @@ const char *otg_state_string(struct musb *musb)
+ #ifdef        CONFIG_USB_MUSB_OTG
+ /*
+- * See also USB_OTG_1-3.pdf 6.6.5 Timers
+- * REVISIT: Are the other timers done in the hardware?
+- */
+-#define TB_ASE0_BRST          100     /* Min 3.125 ms */
+-
+-/*
+  * Handles OTG hnp timeouts, such as b_ase0_brst
+  */
+ void musb_otg_timer_func(unsigned long data)
+@@ -320,10 +315,8 @@ void musb_otg_timer_func(unsigned long data)
+       spin_unlock_irqrestore(&musb->lock, flags);
+ }
+-static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0);
+-
+ /*
+- * Stops the B-device HNP state. Caller must take care of locking.
++ * Stops the HNP transition. Caller must take care of locking.
+  */
+ void musb_hnp_stop(struct musb *musb)
+ {
+@@ -661,11 +654,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                               musb_g_reset(musb);
+                               /* FALLTHROUGH */
+                       case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
+-                              DBG(1, "HNP: Setting timer as %s\n",
+-                                              otg_state_string(musb));
+-                              musb_otg_timer.data = (unsigned long)musb;
+-                              mod_timer(&musb_otg_timer, jiffies
+-                                      + msecs_to_jiffies(100));
++                              /* never use invalid T(a_wait_bcon) */
++                              DBG(1, "HNP: in %s, %d msec timeout\n",
++                                              otg_state_string(musb),
++                                              TA_WAIT_BCON(musb));
++                              mod_timer(&musb->otg_timer, jiffies
++                                      + msecs_to_jiffies(TA_WAIT_BCON(musb)));
+                               break;
+                       case OTG_STATE_A_PERIPHERAL:
+                               musb_hnp_stop(musb);
+@@ -822,9 +816,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ #ifdef        CONFIG_USB_MUSB_OTG
+                               musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+                               DBG(1, "HNP: Setting timer for b_ase0_brst\n");
+-                              musb_otg_timer.data = (unsigned long)musb;
+-                              mod_timer(&musb_otg_timer, jiffies
+-                                      + msecs_to_jiffies(TB_ASE0_BRST));
++                              mod_timer(&musb->otg_timer, jiffies
++                                      + msecs_to_jiffies(
++                                                      OTG_TIME_B_ASE0_BRST));
+ #endif
+                       }
+                       break;
+@@ -1680,7 +1674,8 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
+       }
+       spin_lock_irqsave(&musb->lock, flags);
+-      musb->a_wait_bcon = val;
++      /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
++      musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
+       if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
+               musb->is_active = 0;
+       musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
+@@ -1699,10 +1694,13 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
+       spin_lock_irqsave(&musb->lock, flags);
+       val = musb->a_wait_bcon;
++      /* FIXME get_vbus_status() is normally #defined as false...
++       * and is effectively TUSB-specific.
++       */
+       vbus = musb_platform_get_vbus_status(musb);
+       spin_unlock_irqrestore(&musb->lock, flags);
+-      return sprintf(buf, "Vbus %s, timeout %lu\n",
++      return sprintf(buf, "Vbus %s, timeout %lu msec\n",
+                       vbus ? "on" : "off", val);
+ }
+ static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
+@@ -1775,6 +1773,7 @@ allocate_instance(struct device *dev,
+       hcd->uses_new_polling = 1;
+       musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
++      musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
+ #else
+       musb = kzalloc(sizeof *musb, GFP_KERNEL);
+       if (!musb)
+@@ -1969,6 +1968,10 @@ bad_config:
+       if (status < 0)
+               goto fail2;
++#ifdef CONFIG_USB_OTG
++      setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
++#endif
++
+       /* Init IRQ workqueue before request_irq */
+       INIT_WORK(&musb->irq_work, musb_irq_work);
+diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
+index c3ee348..cf3ccb0 100644
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -40,6 +40,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/smp_lock.h>
+ #include <linux/errno.h>
++#include <linux/timer.h>
+ #include <linux/clk.h>
+ #include <linux/device.h>
+ #include <linux/usb/ch9.h>
+@@ -180,10 +181,15 @@ enum musb_g_ep0_state {
+       MUSB_EP0_STAGE_ACKWAIT,         /* after zlp, before statusin */
+ } __attribute__ ((packed));
+-/* OTG protocol constants */
++/*
++ * OTG protocol constants.  See USB OTG 1.3 spec,
++ * sections 5.5 "Device Timings" and 6.6.5 "Timers".
++ */
+ #define OTG_TIME_A_WAIT_VRISE 100             /* msec (max) */
+-#define OTG_TIME_A_WAIT_BCON  0               /* 0=infinite; min 1000 msec */
+-#define OTG_TIME_A_IDLE_BDIS  200             /* msec (min) */
++#define OTG_TIME_A_WAIT_BCON  1100            /* min 1 second */
++#define OTG_TIME_A_AIDL_BDIS  200             /* min 200 msec */
++#define OTG_TIME_B_ASE0_BRST  100             /* min 3.125 ms */
++
+ /*************************** REGISTER ACCESS ********************************/
+@@ -332,6 +338,8 @@ struct musb {
+       struct list_head        control;        /* of musb_qh */
+       struct list_head        in_bulk;        /* of musb_qh */
+       struct list_head        out_bulk;       /* of musb_qh */
++
++      struct timer_list       otg_timer;
+ #endif
+       /* called with IRQs blocked; ON/nonzero implies starting a session,
+diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
+index 5f67b03..3fbc807 100644
+--- a/drivers/usb/musb/omap2430.c
++++ b/drivers/usb/musb/omap2430.c
+@@ -45,7 +45,6 @@
+ #define       get_cpu_rev()   2
+ #endif
+-#define MUSB_TIMEOUT_A_WAIT_BCON      1100
+ static struct timer_list musb_idle_timer;
+@@ -246,7 +245,6 @@ int __init musb_platform_init(struct musb *musb)
+       if (is_host_enabled(musb))
+               musb->board_set_vbus = omap_set_vbus;
+-      musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
+       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch
new file mode 100644 (file)
index 0000000..6269016
--- /dev/null
@@ -0,0 +1,133 @@
+From a637c5056ef52fbb7c41eb7537a9ec3d150231ad Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Thu, 2 Apr 2009 10:16:11 -0700
+Subject: [PATCH] musb: make initial HNP roleswitch work (v2)
+
+Minor HNP bugfixes, so the initial role switch works:
+
+ - A-Device:
+     * disconnect-during-suspend enters A_PERIPHERAL state
+     * kill OTG timer after reset as A_PERIPHERAL ...
+     * ... and also pass that reset to the gadget
+     * once HNP succeeds, clear the "ignore_disconnect" flag
+     * from A_PERIPHERAL, disconnect transitions to A_WAIT_BCON
+
+ - B-Device:
+     * kill OTG timer on entry to B_HOST state (HNP succeeded)
+     * once HNP succeeds, clear "ignore_disconnect" flag
+     * kick the root hub only _after_ the state is adjusted
+
+Other state transitions are left alone.  Notably, exit paths from
+the "roles have switched" state ... A_PERIPHERAL handling of that
+stays seriously broken.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_core.c    |   27 ++++++++++++++++-----------
+ drivers/usb/musb/musb_gadget.c  |    2 +-
+ drivers/usb/musb/musb_virthub.c |   11 ++++++++++-
+ 3 files changed, 27 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index 05c5dd3..9dc995a 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -587,28 +587,23 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+               if (devctl & MUSB_DEVCTL_LSDEV)
+                       musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+-              if (hcd->status_urb)
+-                      usb_hcd_poll_rh_status(hcd);
+-              else
+-                      usb_hcd_resume_root_hub(hcd);
+-
+-              MUSB_HST_MODE(musb);
+-
+               /* indicate new connection to OTG machine */
+               switch (musb->xceiv->state) {
+               case OTG_STATE_B_PERIPHERAL:
+                       if (int_usb & MUSB_INTR_SUSPEND) {
+                               DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
+-                              musb->xceiv->state = OTG_STATE_B_HOST;
+-                              hcd->self.is_b_host = 1;
+                               int_usb &= ~MUSB_INTR_SUSPEND;
++                              goto b_host;
+                       } else
+                               DBG(1, "CONNECT as b_peripheral???\n");
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+-                      DBG(1, "HNP: Waiting to switch to b_host state\n");
++                      DBG(1, "HNP: CONNECT, now b_host\n");
++b_host:
+                       musb->xceiv->state = OTG_STATE_B_HOST;
+                       hcd->self.is_b_host = 1;
++                      musb->ignore_disconnect = 0;
++                      del_timer(&musb->otg_timer);
+                       break;
+               default:
+                       if ((devctl & MUSB_DEVCTL_VBUS)
+@@ -618,6 +613,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                       }
+                       break;
+               }
++
++              /* poke the root hub */
++              MUSB_HST_MODE(musb);
++              if (hcd->status_urb)
++                      usb_hcd_poll_rh_status(hcd);
++              else
++                      usb_hcd_resume_root_hub(hcd);
++
+               DBG(1, "CONNECT (%s) devctl %02x\n",
+                               otg_state_string(musb), devctl);
+       }
+@@ -662,7 +665,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+                                       + msecs_to_jiffies(TA_WAIT_BCON(musb)));
+                               break;
+                       case OTG_STATE_A_PERIPHERAL:
+-                              musb_hnp_stop(musb);
++                              musb->ignore_disconnect = 0;
++                              del_timer(&musb->otg_timer);
++                              musb_g_reset(musb);
+                               break;
+                       case OTG_STATE_B_WAIT_ACON:
+                               DBG(1, "HNP: RESET (%s), to b_peripheral\n",
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index 2fbfba5..7dd3d59 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -1964,7 +1964,7 @@ void musb_g_disconnect(struct musb *musb)
+               musb->xceiv->state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+-              musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
++              musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_HOST:
+diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
+index 7e7900f..14f7cf3 100644
+--- a/drivers/usb/musb/musb_virthub.c
++++ b/drivers/usb/musb/musb_virthub.c
+@@ -187,8 +187,17 @@ void musb_root_disconnect(struct musb *musb)
+       musb->is_active = 0;
+       switch (musb->xceiv->state) {
+-      case OTG_STATE_A_HOST:
+       case OTG_STATE_A_SUSPEND:
++#ifdef        CONFIG_USB_MUSB_OTG
++              if (is_otg_enabled(musb)
++                              && musb->xceiv->host->b_hnp_enable) {
++                      musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
++                      musb->g.is_a_peripheral = 1;
++                      break;
++              }
++#endif
++              /* FALLTHROUGH */
++      case OTG_STATE_A_HOST:
+               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+               musb->is_active = 0;
+               break;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-omap-pm-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch b/recipes/linux/linux-omap-pm-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch
new file mode 100644 (file)
index 0000000..fc34fb9
--- /dev/null
@@ -0,0 +1,145 @@
+From 4288b7df4ae6629a4fb14aca2c489da01d4d19c3 Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Tue, 31 Mar 2009 12:35:09 -0700
+Subject: [PATCH] musb: support disconnect after HNP roleswitch
+
+Adjust HNP state machines in MUSB driver so that they handle the
+case where the cable is disconnected.  The A-side machine was
+very wrong (unrecoverable); the B-Side was much less so.
+
+ - A_PERIPHERAL ... as usual, the non-observability of the ID
+   pin through Mentor's registers makes trouble.  We can't go
+   directly to A_WAIT_VFALL to end the session and start the
+   disconnect processing.  We can however sense link suspending,
+   go to A_WAIT_BCON, and from there use OTG timeouts to finally
+   trigger that A_WAIT_VFALL transition.  (Hoping that nobody
+   reconnects quickly to that port and notices the wrong state.)
+
+ - B_HOST ... actually clear the Host Request (HR) bit as the
+   messages say, disconnect the peripheral from the root hub,
+   and don't detour through a suspend state.  (In some cases
+   this would eventually have cleaned up.)
+
+Also adjust the A_SUSPEND transition to respect the A_AIDL_BDIS
+timeout, so if HNP doesn't trigger quickly enough the A_WAIT_VFALL
+transition happens as it should.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/musb_core.c    |   41 +++++++++++++++++++++++++++-----------
+ drivers/usb/musb/musb_gadget.c  |    2 +
+ drivers/usb/musb/musb_virthub.c |    4 +++
+ 3 files changed, 35 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index 9dc995a..5770ccb 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -304,9 +304,11 @@ void musb_otg_timer_func(unsigned long data)
+               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+               musb->is_active = 0;
+               break;
++      case OTG_STATE_A_SUSPEND:
+       case OTG_STATE_A_WAIT_BCON:
+-              DBG(1, "HNP: a_wait_bcon timeout; back to a_host\n");
+-              musb_hnp_stop(musb);
++              DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
++              musb_set_vbus(musb, 0);
++              musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+               break;
+       default:
+               DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb));
+@@ -324,15 +326,12 @@ void musb_hnp_stop(struct musb *musb)
+       void __iomem    *mbase = musb->mregs;
+       u8      reg;
++      DBG(1, "HNP: stop from %s\n", otg_state_string(musb));
++
+       switch (musb->xceiv->state) {
+       case OTG_STATE_A_PERIPHERAL:
+-      case OTG_STATE_A_WAIT_VFALL:
+-      case OTG_STATE_A_WAIT_BCON:
+-              DBG(1, "HNP: Switching back to A-host\n");
+               musb_g_disconnect(musb);
+-              musb->xceiv->state = OTG_STATE_A_IDLE;
+-              MUSB_HST_MODE(musb);
+-              musb->is_active = 0;
++              DBG(1, "HNP: back to %s\n", otg_state_string(musb));
+               break;
+       case OTG_STATE_B_HOST:
+               DBG(1, "HNP: Disabling HR\n");
+@@ -775,7 +774,16 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ #endif        /* HOST */
+ #ifdef CONFIG_USB_MUSB_OTG
+               case OTG_STATE_B_HOST:
+-                      musb_hnp_stop(musb);
++                      /* REVISIT this behaves for "real disconnect"
++                       * cases; make sure the other transitions from
++                       * from B_HOST act right too.  The B_HOST code
++                       * in hnp_stop() is currently not used...
++                       */
++                      musb_root_disconnect(musb);
++                      musb_to_hcd(musb)->self.is_b_host = 0;
++                      musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
++                      MUSB_DEV_MODE(musb);
++                      musb_g_disconnect(musb);
+                       break;
+               case OTG_STATE_A_PERIPHERAL:
+                       musb_hnp_stop(musb);
+@@ -807,10 +815,19 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+               switch (musb->xceiv->state) {
+ #ifdef        CONFIG_USB_MUSB_OTG
+               case OTG_STATE_A_PERIPHERAL:
+-                      /*
+-                       * We cannot stop HNP here, devctl BDEVICE might be
+-                       * still set.
++                      /* We also come here if the cable is removed, since
++                       * this silicon doesn't report ID-no-longer-grounded.
++                       *
++                       * We depend on T(a_wait_bcon) to shut us down, and
++                       * hope users don't do anything dicey during this
++                       * undesired detour through A_WAIT_BCON.
+                        */
++                      musb_hnp_stop(musb);
++                      usb_hcd_resume_root_hub(musb_to_hcd(musb));
++                      musb_root_disconnect(musb);
++                      musb_platform_try_idle(musb, jiffies
++                                      + msecs_to_jiffies(musb->a_wait_bcon
++                                              ? : OTG_TIME_A_WAIT_BCON));
+                       break;
+ #endif
+               case OTG_STATE_B_PERIPHERAL:
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index 7dd3d59..8b3c4e2 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -1962,9 +1962,11 @@ void musb_g_disconnect(struct musb *musb)
+               DBG(2, "Unhandled disconnect %s, setting a_idle\n",
+                       otg_state_string(musb));
+               musb->xceiv->state = OTG_STATE_A_IDLE;
++              MUSB_HST_MODE(musb);
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
++              MUSB_HST_MODE(musb);
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_HOST:
+diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
+index 14f7cf3..e8ef925 100644
+--- a/drivers/usb/musb/musb_virthub.c
++++ b/drivers/usb/musb/musb_virthub.c
+@@ -83,6 +83,10 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
+                       musb->xceiv->state = OTG_STATE_A_SUSPEND;
+                       musb->is_active = is_otg_enabled(musb)
+                                       && musb->xceiv->host->b_hnp_enable;
++                      if (musb->is_active)
++                              mod_timer(&musb->otg_timer, jiffies
++                                      + msecs_to_jiffies(
++                                              OTG_TIME_A_AIDL_BDIS));
+                       musb_platform_try_idle(musb, 0);
+                       break;
+ #ifdef        CONFIG_USB_MUSB_OTG
+-- 
+1.6.0.4
+
index e066536..3a587b2 100644 (file)
@@ -126,6 +126,37 @@ SRC_URI_append = " \
            file://vfp/04-vfp-threads.patch;patch=1 \
            file://vfp/05-vfp-signal-handlers.patch;patch=1 \
            file://arch-has-holes.diff;patch=1 \
+           file://musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch;patch=1 \
+           file://musb/0002-USB-composite-avoid-inconsistent-lock-state.patch;patch=1 \
+           file://musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch;patch=1 \
+           file://musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch;patch=1 \
+           file://musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch;patch=1 \
+           file://musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch;patch=1 \
+           file://musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch;patch=1 \
+           file://musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch;patch=1 \
+           file://musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch;patch=1 \
+           file://musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch;patch=1 \
+           file://musb/0011-musb-fix-isochronous-TXDMA-take-2.patch;patch=1 \
+           file://musb/0012-musb-fix-possible-panic-while-resuming.patch;patch=1 \
+           file://musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch;patch=1 \
+           file://musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch;patch=1 \
+           file://musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch;patch=1 \
+           file://musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch;patch=1 \
+           file://musb/0017-musb_host-refactor-URB-giveback.patch;patch=1 \
+           file://musb/0018-musb-split-out-CPPI-interrupt-handler.patch;patch=1 \
+           file://musb/0019-musb_host-simplify-check-for-active-URB.patch;patch=1 \
+           file://musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch;patch=1 \
+           file://musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch;patch=1 \
+           file://musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch;patch=1 \
+           file://musb/0023-musb-add-high-bandwidth-ISO-support.patch;patch=1 \
+           file://musb/0024-USB-otg-adding-nop-usb-transceiver.patch;patch=1 \
+           file://musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch;patch=1 \
+           file://musb/0026-musb-proper-hookup-to-transceiver-drivers.patch;patch=1 \
+           file://musb/0027-musb-otg-timer-cleanup.patch;patch=1 \
+           file://musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch;patch=1 \
+           file://musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch;patch=1 \
+           file://cache/l1cache-shift.patch;patch=1 \
+           file://cache/copy-page-tweak.patch;patch=1 \
 "
 
 
index 9f390d4..18382b6 100644 (file)
@@ -163,6 +163,8 @@ SRC_URI_append = " \
            file://vfp/04-vfp-threads.patch;patch=1 \
            file://vfp/05-vfp-signal-handlers.patch;patch=1 \
            file://arch-has-holes.diff;patch=1 \
+           file://cache/l1cache-shift.patch;patch=1 \
+           file://cache/copy-page-tweak.patch;patch=1 \
 "