public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] musb: add musb support for AM35x
@ 2010-02-24 13:18 Ajay Kumar Gupta
       [not found] ` <1267017527-17591-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Ajay Kumar Gupta @ 2010-02-24 13:18 UTC (permalink / raw)
  To: linux-usb; +Cc: linux-omap, Ajay Kumar Gupta

AM35x has musb interface and uses CPPI4.1 DMA engine.
Current patch supports only PIO mode and there are on-going
discussions on location of CPPI4.1 DMA.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
---
 drivers/usb/musb/Kconfig     |    4 +-
 drivers/usb/musb/Makefile    |    4 +
 drivers/usb/musb/am3517.c    |  536 ++++++++++++++++++++++++++++++++++++++++++
 drivers/usb/musb/musb_core.c |    3 +-
 4 files changed, 544 insertions(+), 3 deletions(-)
 create mode 100644 drivers/usb/musb/am3517.c

diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index b4c783c..a29cf84 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -10,7 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
 config USB_MUSB_HDRC
 	depends on (USB || USB_GADGET)
 	depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
-	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
+	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN || MACH_OMAP3517EVM)
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	select USB_OTG_UTILS
 	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
@@ -140,7 +140,7 @@ config USB_MUSB_HDRC_HCD
 config MUSB_PIO_ONLY
 	bool 'Disable DMA (always use PIO)'
 	depends on USB_MUSB_HDRC
-	default y if USB_TUSB6010
+	default USB_TUSB6010 || MACH_OMAP3517EVM
 	help
 	  All data is copied between memory and FIFO by the CPU.
 	  DMA controllers are ignored.
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 85710cc..9263033 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -19,7 +19,11 @@ ifeq ($(CONFIG_ARCH_OMAP2430),y)
 endif
 
 ifeq ($(CONFIG_ARCH_OMAP3430),y)
+   ifeq ($(CONFIG_MACH_OMAP3517EVM),y)
+	musb_hdrc-objs  += am3517.o
+   else
 	musb_hdrc-objs	+= omap2430.o
+   endif
 endif
 
 ifeq ($(CONFIG_BF54x),y)
diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
new file mode 100644
index 0000000..913a294
--- /dev/null
+++ b/drivers/usb/musb/am3517.c
@@ -0,0 +1,536 @@
+/*
+ * Texas Instruments AM3517 "glue layer"
+ *
+ * Copyright (c) 2010, by Texas Instruments
+ *
+ * Based on the DA8xx "glue layer" code.
+ * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (c) 2008, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/control.h>
+#include <plat/usb.h>
+
+#include "musb_core.h"
+
+/*
+ * AM3517 specific definitions
+ */
+
+/* CPPI 4.1 queue manager registers */
+#define QMGR_PEND0_REG		0x4090
+#define QMGR_PEND1_REG		0x4094
+#define QMGR_PEND2_REG		0x4098
+
+/* USB 2.0 PHY Control */
+#define CONF2_PHY_GPIOMODE     (1 << 23)
+#define CONF2_OTGMODE          (3 << 14)
+#define CONF2_SESENDEN         (1 << 13)
+#define CONF2_VBDTCTEN         (1 << 12)
+#define CONF2_REFFREQ_24MHZ    (2 << 8)
+#define CONF2_REFFREQ_26MHZ    (7 << 8)
+#define CONF2_REFFREQ_13MHZ    (6 << 8)
+#define CONF2_REFFREQ          (0xf << 8)
+#define CONF2_PHYCLKGD         (1 << 7)
+#define CONF2_VBUSSENSE        (1 << 6)
+#define CONF2_PHY_PLLON        (1 << 5)
+#define CONF2_RESET            (1 << 4)
+#define CONF2_PHYPWRDN         (1 << 3)
+#define CONF2_OTGPWRDN         (1 << 2)
+#define CONF2_DATPOL           (1 << 1)
+
+
+#define AM3517_TX_EP_MASK	0xffff		/* EP0 + 15 Tx EPs */
+#define AM3517_RX_EP_MASK	0xfffe		/* 15 Rx EPs */
+
+#define AM3517_TX_INTR_MASK	(AM3517_TX_EP_MASK << USB_INTR_TX_SHIFT)
+#define AM3517_RX_INTR_MASK	(AM3517_RX_EP_MASK << USB_INTR_RX_SHIFT)
+
+#define A_WAIT_BCON_TIMEOUT	1100	/* in ms */
+
+static inline void phy_on(void)
+{
+	u32 devconf2;
+
+	/*
+	 * Start the on-chip PHY and its PLL.
+	 */
+	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+	devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN |
+			CONF2_OTGMODE | CONF2_REFFREQ | CONF2_PHY_GPIOMODE);
+	devconf2 |= CONF2_SESENDEN | CONF2_VBDTCTEN | CONF2_PHY_PLLON |
+		    CONF2_REFFREQ_13MHZ | CONF2_DATPOL;
+
+	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+
+	DBG(1, "Waiting for PHY clock good...\n");
+	while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
+			& CONF2_PHYCLKGD))
+		cpu_relax();
+}
+
+static inline void phy_off(void)
+{
+	u32 devconf2;
+
+	/*
+	 * Power down the on-chip PHY.
+	 */
+	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+	devconf2 &= ~CONF2_PHY_PLLON;
+	devconf2 |=  CONF2_PHYPWRDN | CONF2_OTGPWRDN;
+	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+}
+
+/**
+ * musb_platform_enable - enable interrupts
+ */
+void musb_platform_enable(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+	u32 epmask, coremask;
+
+	/* Workaround: setup IRQs through both register sets. */
+	epmask = ((musb->epmask & AM3517_TX_EP_MASK) << USB_INTR_TX_SHIFT) |
+	       ((musb->epmask & AM3517_RX_EP_MASK) << USB_INTR_RX_SHIFT);
+	coremask = (0x01ff << USB_INTR_USB_SHIFT);
+
+	musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
+	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, coremask);
+
+	/* Force the DRVVBUS IRQ so we can start polling for ID change. */
+	if (is_otg_enabled(musb))
+		musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
+			    USB_INTR_DRVVBUS << USB_INTR_USB_SHIFT);
+}
+
+/**
+ * musb_platform_disable - disable HDRC and flush interrupts
+ */
+void musb_platform_disable(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+
+	musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, USB_INTR_USB_MASK);
+	musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG,
+			 AM3517_TX_INTR_MASK | AM3517_RX_INTR_MASK);
+	musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
+	musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
+}
+
+static int vbus_state = -1;
+
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+#define portstate(stmt) 	stmt
+#else
+#define portstate(stmt)
+#endif
+
+static void am3517_source_power(struct musb *musb, int is_on, int immediate)
+{
+	if (is_on)
+		is_on = 1;
+
+	if (vbus_state == is_on)
+		return;
+	vbus_state = is_on;
+}
+
+static void am3517_set_vbus(struct musb *musb, int is_on)
+{
+	WARN_ON(is_on && is_peripheral_active(musb));
+	am3517_source_power(musb, is_on, 0);
+}
+
+#define	POLL_SECONDS	2
+
+static struct timer_list otg_workaround;
+
+static void otg_timer(unsigned long _musb)
+{
+	struct musb		*musb = (void *)_musb;
+	void __iomem		*mregs = musb->mregs;
+	u8			devctl;
+	unsigned long		flags;
+
+	/* We poll because AM3517's won't expose several OTG-critical
+	* status change events (from the transceiver) otherwise.
+	 */
+	devctl = musb_readb(mregs, MUSB_DEVCTL);
+	DBG(7, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
+
+	spin_lock_irqsave(&musb->lock, flags);
+	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_DEV_MODE(musb);
+		} else {
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+			MUSB_HST_MODE(musb);
+		}
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		/*
+		 * Wait till VBUS falls below SessionEnd (~0.2 V); the 1.3
+		 * RTL seems to mis-handle session "start" otherwise (or in
+		 * our case "recover"), in routine "VBUS was valid by the time
+		 * VBUSERR got reported during enumeration" cases.
+		 */
+		if (devctl & MUSB_DEVCTL_VBUS) {
+			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+			break;
+		}
+		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+		musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG,
+			    MUSB_INTR_VBUSERROR << USB_INTR_USB_SHIFT);
+		break;
+	case OTG_STATE_B_IDLE:
+		if (!is_peripheral_enabled(musb))
+			break;
+
+		/*
+		 * There's no ID-changed IRQ, so we have no good way to tell
+		 * when to switch to the A-Default state machine (by setting
+		 * the DEVCTL.SESSION flag).
+		 *
+		 * Workaround:  whenever we're in B_IDLE, try setting the
+		 * session flag every few seconds.  If it works, ID was
+		 * grounded and we're now in the A-Default state machine.
+		 *
+		 * NOTE: setting the session flag is _supposed_ to trigger
+		 * SRP but clearly it doesn't.
+		 */
+		devctl = musb_readb(mregs, MUSB_DEVCTL);
+		if (devctl & MUSB_DEVCTL_BDEVICE)
+			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+		else
+			musb->xceiv->state = OTG_STATE_A_IDLE;
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+{
+	static unsigned long last_timer;
+
+	if (!is_otg_enabled(musb))
+		return;
+
+	if (timeout == 0)
+		timeout = jiffies + msecs_to_jiffies(3);
+
+	/* 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)) {
+		DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+		del_timer(&otg_workaround);
+		last_timer = jiffies;
+		return;
+	}
+
+	if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
+		DBG(4, "Longer idle timer already pending, ignoring...\n");
+		return;
+	}
+	last_timer = timeout;
+
+	DBG(4, "%s inactive, starting idle timer for %u ms\n",
+	    otg_state_string(musb), jiffies_to_msecs(timeout - jiffies));
+	mod_timer(&otg_workaround, timeout);
+}
+
+static irqreturn_t am3517_interrupt(int irq, void *hci)
+{
+	struct musb  *musb = hci;
+	void __iomem *reg_base = musb->ctrl_base;
+	unsigned long flags;
+	irqreturn_t ret = IRQ_NONE;
+	u32 epintr, usbintr, lvl_intr;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	/* Get endpoint interrupts */
+	epintr = musb_readl(reg_base, EP_INTR_SRC_MASKED_REG);
+
+	if (epintr) {
+		musb_writel(reg_base, EP_INTR_SRC_CLEAR_REG, epintr);
+
+		musb->int_rx =
+			(epintr & AM3517_RX_INTR_MASK) >> USB_INTR_RX_SHIFT;
+		musb->int_tx =
+			(epintr & AM3517_TX_INTR_MASK) >> USB_INTR_TX_SHIFT;
+	}
+
+	/* Get usb core interrupts */
+	usbintr = musb_readl(reg_base, CORE_INTR_SRC_MASKED_REG);
+	if (!usbintr && !epintr)
+		goto eoi;
+
+	if (usbintr) {
+		musb_writel(reg_base, CORE_INTR_SRC_CLEAR_REG, usbintr);
+
+		musb->int_usb =
+			(usbintr & USB_INTR_USB_MASK) >> USB_INTR_USB_SHIFT;
+	}
+	/*
+	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+	 * AM3517's missing ID change IRQ.  We need an ID change IRQ to
+	 * switch appropriately between halves of the OTG state machine.
+	 * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+	 */
+	if (usbintr & (USB_INTR_DRVVBUS << USB_INTR_USB_SHIFT)) {
+		int drvvbus = musb_readl(reg_base, USB_STAT_REG);
+		void __iomem *mregs = musb->mregs;
+		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
+		int err;
+
+		err = is_host_enabled(musb) && (musb->int_usb &
+						MUSB_INTR_VBUSERROR);
+		if (err) {
+			/*
+			 * The Mentor core doesn't debounce VBUS as needed
+			 * to cope with device connect current spikes. This
+			 * means it's not uncommon for bus-powered devices
+			 * to get VBUS errors during enumeration.
+			 *
+			 * This is a workaround, but newer RTL from Mentor
+			 * seems to allow a better one: "re"-starting sessions
+			 * without waiting for VBUS to stop registering in
+			 * devctl.
+			 */
+			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+			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;
+			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;
+			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+		}
+
+		/* NOTE: this must complete power-on within 100 ms. */
+		am3517_source_power(musb, drvvbus, 0);
+		DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
+				drvvbus ? "on" : "off",
+				otg_state_string(musb),
+				err ? " ERROR" : "",
+				devctl);
+		ret = IRQ_HANDLED;
+	}
+
+	if (musb->int_tx || musb->int_rx || musb->int_usb) {
+		irqreturn_t mret;
+
+		mret = musb_interrupt(musb);
+		if (mret == IRQ_HANDLED)
+			ret = IRQ_HANDLED;
+	}
+
+ eoi:
+	/* EOI needs to be written for the IRQ to be re-asserted. */
+	if (ret == IRQ_HANDLED || epintr || usbintr) {
+		/* clear level interrupt */
+		lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+		lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
+		omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
+		/* write EOI */
+		musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
+	}
+
+	/* Poll for ID change */
+	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+
+	spin_unlock_irqrestore(&musb->lock, flags);
+
+	if (ret != IRQ_HANDLED) {
+		if (epintr || usbintr)
+			/*
+			 * We sometimes get unhandled IRQs in the peripheral
+			 * mode from EP0 and SOF...
+			 */
+			DBG(2, "Unhandled USB IRQ %08x-%08x\n",
+					 epintr, usbintr);
+		else if (printk_ratelimit())
+			/*
+			 * We've seen series of spurious interrupts in the
+			 * peripheral mode after USB reset and then after some
+			 * time a real interrupt storm starting...
+			 */
+			DBG(2, "Spurious IRQ\n");
+	}
+	return ret;
+}
+
+int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+{
+	WARNING("FIXME: %s not implemented\n", __func__);
+	return -EIO;
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+	void __iomem *reg_base = musb->ctrl_base;
+	struct clk              *otg_fck;
+	u32 rev, lvl_intr, sw_reset;
+
+	usb_nop_xceiv_register();
+
+	musb->xceiv = otg_get_transceiver();
+	if (!musb->xceiv)
+		return -ENODEV;
+
+	/* Mentor is at offset of 0x400 in AM3517 */
+	musb->mregs += USB_MENTOR_CORE_OFFSET;
+
+	/* musb->clock is already set from board/arch files */
+	if (IS_ERR(musb->clock))
+		return PTR_ERR(musb->clock);
+
+	if (musb->set_clock)
+		musb->set_clock(musb->clock, 1);
+	else
+		clk_enable(musb->clock);
+
+	DBG(2, "usbotg_ck=%lud\n", clk_get_rate(musb->clock));
+	otg_fck = clk_get(musb->controller, "fck");
+	clk_enable(otg_fck);
+
+	DBG(2, "usbotg_phy_ck=%lud\n", clk_get_rate(otg_fck));
+	/* Returns zero if e.g. not clocked */
+	rev = musb_readl(reg_base, USB_REVISION_REG);
+	if (!rev)
+		return -ENODEV;
+
+	if (is_host_enabled(musb))
+		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+
+	musb->board_set_vbus = am3517_set_vbus;
+	am3517_source_power(musb, 0, 1);
+
+	/* global reset */
+	sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+
+	sw_reset |= AM35XX_USBOTGSS_SW_RST;
+	omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
+
+	sw_reset &= ~AM35XX_USBOTGSS_SW_RST;
+	omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
+
+	/* Reset the controller */
+	musb_writel(reg_base, USB_CTRL_REG, USB_SOFT_RESET_MASK);
+
+	/* Start the on-chip PHY and its PLL. */
+	phy_on();
+
+	msleep(15);
+
+	musb->a_wait_bcon = A_WAIT_BCON_TIMEOUT;
+	musb->isr = am3517_interrupt;
+
+	/* clear level interrupt */
+	lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+	lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
+	omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
+
+	return 0;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+	if (is_host_enabled(musb))
+		del_timer_sync(&otg_workaround);
+
+	am3517_source_power(musb, 0 /* off */, 1);
+
+	/* Delay to avoid problems with module reload... */
+	if (is_host_enabled(musb) && musb->xceiv->default_a) {
+		int maxdelay = 30;
+		u8 devctl, warn = 0;
+
+		/*
+		 * If there's no peripheral connected, this can take a
+		 * long time to fall...
+		 */
+		do {
+			devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+			if (!(devctl & MUSB_DEVCTL_VBUS))
+				break;
+			if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
+				warn = devctl & MUSB_DEVCTL_VBUS;
+				DBG(1, "VBUS %d\n",
+					warn >> MUSB_DEVCTL_VBUS_SHIFT);
+			}
+			msleep(1000);
+			maxdelay--;
+		} while (maxdelay > 0);
+
+		/* In OTG mode, another host might be connected... */
+		if (devctl & MUSB_DEVCTL_VBUS)
+			DBG(1, "VBUS off timeout (devctl %02x)\n", devctl);
+	}
+
+	phy_off();
+
+	usb_nop_xceiv_unregister();
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+void musb_platform_save_context(struct musb_context_registers
+		*musb_context)
+{
+	phy_off();
+}
+
+void musb_platform_restore_context(struct musb_context_registers
+		*musb_context)
+{
+	phy_on();
+}
+#endif
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 98fd5b6..f8efe00 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -982,7 +982,8 @@ static void musb_shutdown(struct platform_device *pdev)
  * more than selecting one of a bunch of predefined configurations.
  */
 #if defined(CONFIG_USB_TUSB6010) || \
-	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
+	defined(CONFIG_MACH_OMAP3517EVM)
 static ushort __initdata fifo_mode = 4;
 #else
 static ushort __initdata fifo_mode = 2;
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] AM35x: musb: Workaround for fifo read issue
       [not found] ` <1267017527-17591-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
@ 2010-02-24 13:18   ` Ajay Kumar Gupta
  2010-03-12 14:56   ` [PATCH 1/2] musb: add musb support for AM35x Sergei Shtylyov
  2010-03-12 15:04   ` Sergei Shtylyov
  2 siblings, 0 replies; 6+ messages in thread
From: Ajay Kumar Gupta @ 2010-02-24 13:18 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA, Ajay Kumar Gupta

AM35x supports only 32bit read operations so we need to have
workaround for 8bit and 16bit read operations.

Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
---
 drivers/usb/musb/am3517.c    |   30 ++++++++++++++++++++++++++++++
 drivers/usb/musb/musb_core.c |    2 ++
 2 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
index 913a294..1326089 100644
--- a/drivers/usb/musb/am3517.c
+++ b/drivers/usb/musb/am3517.c
@@ -534,3 +534,33 @@ void musb_platform_restore_context(struct musb_context_registers
 	phy_on();
 }
 #endif
+
+/* AM35x supports only 32bit read operation */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+	void __iomem *fifo = hw_ep->fifo;
+	u32		val;
+	int		i;
+
+	/* Read for 32bit-aligned destination address */
+	if ((likely((0x03 & (unsigned long) dst) == 0)) && len >= 4) {
+		readsl(fifo, dst, len >> 2);
+		dst += (len & ~0x03);
+		len &= 0x03;
+	}
+	/* Now read the rest 1 to 3 bytes or complete length if
+	 * unaligned address.
+	 */
+	if (len > 4) {
+		for (i = 0; i < (len >> 2); i++) {
+			val = musb_readl(fifo, 0);
+			memcpy(dst, &val, 4);
+			dst += 4;
+		}
+		len %= 4;
+	}
+	if (len > 0) {
+		val = musb_readl(fifo, 0);
+		memcpy(dst, &val, len);
+	}
+}
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index f8efe00..2c1b3ab 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -191,6 +191,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
 	}
 }
 
+#if !defined(CONFIG_MACH_OMAP3517EVM)
 /*
  * Unload an endpoint's FIFO
  */
@@ -228,6 +229,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 		readsb(fifo, dst, len);
 	}
 }
+#endif
 
 #endif	/* normal PIO */
 
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] musb: add musb support for AM35x
       [not found] ` <1267017527-17591-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  2010-02-24 13:18   ` [PATCH 2/2] AM35x: musb: Workaround for fifo read issue Ajay Kumar Gupta
@ 2010-03-12 14:56   ` Sergei Shtylyov
       [not found]     ` <4B9A560B.7010908-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
  2010-03-12 15:04   ` Sergei Shtylyov
  2 siblings, 1 reply; 6+ messages in thread
From: Sergei Shtylyov @ 2010-03-12 14:56 UTC (permalink / raw)
  To: Ajay Kumar Gupta
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA

Hello.

Ajay Kumar Gupta wrote:

> AM35x has musb interface and uses CPPI4.1 DMA engine.
> Current patch supports only PIO mode and there are on-going
> discussions on location of CPPI4.1 DMA.
>
> Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
> ---
>  drivers/usb/musb/Kconfig     |    4 +-
>  drivers/usb/musb/Makefile    |    4 +
>  drivers/usb/musb/am3517.c    |  536 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/musb/musb_core.c |    3 +-
>  4 files changed, 544 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/usb/musb/am3517.c
>
> diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
> index b4c783c..a29cf84 100644
> --- a/drivers/usb/musb/Kconfig
> +++ b/drivers/usb/musb/Kconfig
> @@ -10,7 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
>  config USB_MUSB_HDRC
>  	depends on (USB || USB_GADGET)
>  	depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
> -	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
> +	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN || MACH_OMAP3517EVM)
>  	select TWL4030_USB if MACH_OMAP_3430SDP
>  	select USB_OTG_UTILS
>  	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
> @@ -140,7 +140,7 @@ config USB_MUSB_HDRC_HCD
>  config MUSB_PIO_ONLY
>  	bool 'Disable DMA (always use PIO)'
>  	depends on USB_MUSB_HDRC
> -	default y if USB_TUSB6010
> +	default USB_TUSB6010 || MACH_OMAP3517EVM
>  	help
>  	  All data is copied between memory and FIFO by the CPU.
>  	  DMA controllers are ignored.
> diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
> index 85710cc..9263033 100644
> --- a/drivers/usb/musb/Makefile
> +++ b/drivers/usb/musb/Makefile
> @@ -19,7 +19,11 @@ ifeq ($(CONFIG_ARCH_OMAP2430),y)
>  endif
>  
>  ifeq ($(CONFIG_ARCH_OMAP3430),y)
> +   ifeq ($(CONFIG_MACH_OMAP3517EVM),y)
> +	musb_hdrc-objs  += am3517.o
>   

   Isn't there some ARCH-level option for AM3517 SoC? Depending on the 
board type doesn't really scale well...

> +   else
>  	musb_hdrc-objs	+= omap2430.o
> +   endif
>  endif
>  
>  ifeq ($(CONFIG_BF54x),y)
> diff --git a/drivers/usb/musb/am3517.c b/drivers/usb/musb/am3517.c
> new file mode 100644
> index 0000000..913a294
> --- /dev/null
> +++ b/drivers/usb/musb/am3517.c
> @@ -0,0 +1,536 @@
>   
[...]
> +/*
> + * AM3517 specific definitions
> + */
> +
> +/* CPPI 4.1 queue manager registers */
> +#define QMGR_PEND0_REG		0x4090
> +#define QMGR_PEND1_REG		0x4094
> +#define QMGR_PEND2_REG		0x4098
>   

   Those are not used (yet)...

> +static inline void phy_on(void)
> +{
> +	u32 devconf2;
> +
> +	/*
> +	 * Start the on-chip PHY and its PLL.
> +	 */
> +	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
> +
> +	devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN |
> +			CONF2_OTGMODE | CONF2_REFFREQ | CONF2_PHY_GPIOMODE);
>   

   Shouldn't you manipulate CONF2_OTGMODE in the board code instead? I 
suspect value of 0 doesn't fit the host-only configuration (without 
cable connected, MUSB will think it's a B-device, and the driver will 
fail to initialize IIRC).

> +	devconf2 |= CONF2_SESENDEN | CONF2_VBDTCTEN | CONF2_PHY_PLLON |
> +		    CONF2_REFFREQ_13MHZ | CONF2_DATPOL;
>   

   Reference clock of 13 MHz, not 12? Hmm... Again, shouldn't the board 
code select the reference frequency (clock might be external, IIUC)?

> +static inline void phy_off(void)
> +{
> +	u32 devconf2;
> +
> +	/*
> +	 * Power down the on-chip PHY.
> +	 */
> +	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
> +
> +	devconf2 &= ~CONF2_PHY_PLLON;
> +	devconf2 |=  CONF2_PHYPWRDN | CONF2_OTGPWRDN;
> +	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
> +}
> +
> +/**
> + * musb_platform_enable - enable interrupts
> + */
> +void musb_platform_enable(struct musb *musb)
> +{
> +	void __iomem *reg_base = musb->ctrl_base;
> +	u32 epmask, coremask;
> +
> +	/* Workaround: setup IRQs through both register sets. */
> +	epmask = ((musb->epmask & AM3517_TX_EP_MASK) << USB_INTR_TX_SHIFT) |
> +	       ((musb->epmask & AM3517_RX_EP_MASK) << USB_INTR_RX_SHIFT);
> +	coremask = (0x01ff << USB_INTR_USB_SHIFT);
> +
> +	musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
> +	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, coremask);
>   

   Hm, and I thought all CPPI 4.1 based controllers have the same 
register layout... alas, I was wrong.

> +static int vbus_state = -1;
>   
[...]
> +static void am3517_source_power(struct musb *musb, int is_on, int immediate)
> +{
> +	if (is_on)
> +		is_on = 1;
> +
> +	if (vbus_state == is_on)
> +		return;
> +	vbus_state = is_on;
> +}
> +
>   

   Without the real GPIOs to manipulate, I don't understand the purpose 
of this function...

> +static struct timer_list otg_workaround;
> +
> +static void otg_timer(unsigned long _musb)
> +{
> +	struct musb		*musb = (void *)_musb;
> +	void __iomem		*mregs = musb->mregs;
> +	u8			devctl;
> +	unsigned long		flags;
> +
> +	/* We poll because AM3517's won't expose several OTG-critical
> +	* status change events (from the transceiver) otherwise.
>   

   Need one more space before *...

> +	case OTG_STATE_A_WAIT_VFALL:
> +		/*
> +		 * Wait till VBUS falls below SessionEnd (~0.2 V); the 1.3
> +		 * RTL seems to mis-handle session "start" otherwise (or in
> +		 * our case "recover"), in routine "VBUS was valid by the time
> +		 * VBUSERR got reported during enumeration" cases.
> +		 */
>   

   I wonder if all this still true for RTL 1.8 on which DA8xx (and 
probably AM3517) MUSB is based...

> +void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
> +{
>   

   I wonder how DaVinci gets about without musb_platfrom_try_idle()...

> +static irqreturn_t am3517_interrupt(int irq, void *hci)
> +{

> +		/* NOTE: this must complete power-on within 100 ms. */
> +		am3517_source_power(musb, drvvbus, 0);
>   

   This call is effectively a NOP.

> +	if (musb->int_tx || musb->int_rx || musb->int_usb) {
> +		irqreturn_t mret;
> +
> +		mret = musb_interrupt(musb);
> +		if (mret == IRQ_HANDLED)
> +			ret = IRQ_HANDLED;
>   

   Not sure why you didn't like ret |= musb_interrupt(musb)...

> +	if (ret != IRQ_HANDLED) {
> +		if (epintr || usbintr)
> +			/*
> +			 * We sometimes get unhandled IRQs in the peripheral
> +			 * mode from EP0 and SOF...
> +			 */
> +			DBG(2, "Unhandled USB IRQ %08x-%08x\n",
> +					 epintr, usbintr);
>   

   This check shouldn't be needed any more -- EP0 spurious interrupts 
have been all chased down...

> +		else if (printk_ratelimit())
> +			/*
> +			 * We've seen series of spurious interrupts in the
> +			 * peripheral mode after USB reset and then after some
> +			 * time a real interrupt storm starting...
> +			 */
> +			DBG(2, "Spurious IRQ\n");
>   

   Those turned out to be interrupts caused by CPPI 4.1 descriptor 
starvation (for which the controller didn't even have an interrupt bit). 
I still haven't dealt with them...

> +	}
> +	return ret;
> +}
> +
> +int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
> +{
> +	WARNING("FIXME: %s not implemented\n", __func__);
> +	return -EIO;
>   

   Could be implemented using CONF2_OTGMODE...

> +int __init musb_platform_init(struct musb *musb)
> +{
> +	void __iomem *reg_base = musb->ctrl_base;
> +	struct clk              *otg_fck;
> +	u32 rev, lvl_intr, sw_reset;
> +
> +	usb_nop_xceiv_register();
> +
> +	musb->xceiv = otg_get_transceiver();
> +	if (!musb->xceiv)
> +		return -ENODEV;
> +
> +	/* Mentor is at offset of 0x400 in AM3517 */
> +	musb->mregs += USB_MENTOR_CORE_OFFSET;
> +
> +	/* musb->clock is already set from board/arch files */
> +	if (IS_ERR(musb->clock))
> +		return PTR_ERR(musb->clock);
>   

  This is checked by musb_core.c now, no need to duplicate...

> +	if (musb->set_clock)
> +		musb->set_clock(musb->clock, 1);
>   

   musb->set_clock() is about to be dropped...

> +	else
> +		clk_enable(musb->clock);
> +
> +	DBG(2, "usbotg_ck=%lud\n", clk_get_rate(musb->clock));
>   

   I'd put an empty line after that DBG() rather than before.

> +	otg_fck = clk_get(musb->controller, "fck");
> +	clk_enable(otg_fck);
>   

   Oh, it needs two clocks... Another argument against Felipe dropping 
plat->clock. :-)

> +
> +	DBG(2, "usbotg_phy_ck=%lud\n", clk_get_rate(otg_fck));
>   

   Same about empty line here...

> +	am3517_source_power(musb, 0, 1);
>   

   Effective NOP...

> +	/* Start the on-chip PHY and its PLL. */
> +	phy_on();
> +
> +	msleep(15);
>   

   5 ms is not enough?

> +	musb->a_wait_bcon = A_WAIT_BCON_TIMEOUT;
>   

   Hm... that line kept causing a stream of kernel messages for me, 
until I removed it. Doesn't it for you?

> diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
> index 98fd5b6..f8efe00 100644
> --- a/drivers/usb/musb/musb_core.c
> +++ b/drivers/usb/musb/musb_core.c
> @@ -982,7 +982,8 @@ static void musb_shutdown(struct platform_device *pdev)
>   * more than selecting one of a bunch of predefined configurations.
>   */
>  #if defined(CONFIG_USB_TUSB6010) || \
> -	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
> +	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
> +	defined(CONFIG_MACH_OMAP3517EVM)
>   

   Isn't that dependency already covered by CONFIG_ARCH_OMAP3? Or else I 
don't see you adding your #ifdef around musb_platfrom_try_idle() 
declaration...

WBR, Sergei

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] musb: add musb support for AM35x
       [not found] ` <1267017527-17591-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
  2010-02-24 13:18   ` [PATCH 2/2] AM35x: musb: Workaround for fifo read issue Ajay Kumar Gupta
  2010-03-12 14:56   ` [PATCH 1/2] musb: add musb support for AM35x Sergei Shtylyov
@ 2010-03-12 15:04   ` Sergei Shtylyov
  2 siblings, 0 replies; 6+ messages in thread
From: Sergei Shtylyov @ 2010-03-12 15:04 UTC (permalink / raw)
  To: Ajay Kumar Gupta
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA

Ajay Kumar Gupta wrote:

> AM35x has musb interface and uses CPPI4.1 DMA engine.
> Current patch supports only PIO mode and there are on-going
> discussions on location of CPPI4.1 DMA.
>
> Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>

   Overlooked one thing...

[...]

> +int musb_platform_exit(struct musb *musb)
> +{
>   
[...]
> +	phy_off();
> +
> +	usb_nop_xceiv_unregister();
> +
> +	return 0;
>   

   You forgot the calls to clk_disable() for both your clocks...

> +}
> +
>   
WBR, Sergei

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH 1/2] musb: add musb support for AM35x
       [not found]     ` <4B9A560B.7010908-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
@ 2010-03-15  5:10       ` Gupta, Ajay Kumar
  2010-03-26 19:29         ` Sergei Shtylyov
  0 siblings, 1 reply; 6+ messages in thread
From: Gupta, Ajay Kumar @ 2010-03-15  5:10 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

Hi,
> > AM35x has musb interface and uses CPPI4.1 DMA engine.
> > Current patch supports only PIO mode and there are on-going
> > discussions on location of CPPI4.1 DMA.
> >
> > Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
> >  	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
> > @@ -140,7 +140,7 @@ config USB_MUSB_HDRC_HCD
> >  config MUSB_PIO_ONLY
> >  	bool 'Disable DMA (always use PIO)'
> >  	depends on USB_MUSB_HDRC
> > -	default y if USB_TUSB6010
> > +	default USB_TUSB6010 || MACH_OMAP3517EVM
> >  	help
> >  	  All data is copied between memory and FIFO by the CPU.
> >  	  DMA controllers are ignored.
> > diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
> > index 85710cc..9263033 100644
> > --- a/drivers/usb/musb/Makefile
> > +++ b/drivers/usb/musb/Makefile
> > @@ -19,7 +19,11 @@ ifeq ($(CONFIG_ARCH_OMAP2430),y)
> >  endif
> >
> >  ifeq ($(CONFIG_ARCH_OMAP3430),y)
> > +   ifeq ($(CONFIG_MACH_OMAP3517EVM),y)
> > +	musb_hdrc-objs  += am3517.o
> >
> 
>    Isn't there some ARCH-level option for AM3517 SoC? Depending on the
> board type doesn't really scale well...

AM3517 is actually based on OMAP3 but musb is different. Unfortunately there
is no seperate *_ARCH_* defines for AM3517 alone.

> > + * AM3517 specific definitions
> > + */
> > +
> > +/* CPPI 4.1 queue manager registers */
> > +#define QMGR_PEND0_REG		0x4090
> > +#define QMGR_PEND1_REG		0x4094
> > +#define QMGR_PEND2_REG		0x4098
> >
> 
>    Those are not used (yet)...

Yes, but I added them as they are part of register layout.

> 
> > +static inline void phy_on(void)
> > +{
> > +	u32 devconf2;
> > +
> > +	/*
> > +	 * Start the on-chip PHY and its PLL.
> > +	 */
> > +	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
> > +
> > +	devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN |
> > +			CONF2_OTGMODE | CONF2_REFFREQ | CONF2_PHY_GPIOMODE);
> >
> 
>    Shouldn't you manipulate CONF2_OTGMODE in the board code instead? I
> suspect value of 0 doesn't fit the host-only configuration (without
> cable connected, MUSB will think it's a B-device, and the driver will
> fail to initialize IIRC).

I didn't see any issue in Host/Device only and OTG mode configurations
On AM3517? Did you see any issue on DA8xx?

> 
> > +	devconf2 |= CONF2_SESENDEN | CONF2_VBDTCTEN | CONF2_PHY_PLLON |
> > +		    CONF2_REFFREQ_13MHZ | CONF2_DATPOL;
> >
> 
>    Reference clock of 13 MHz, not 12? Hmm... Again, shouldn't the board
> code select the reference frequency (clock might be external, IIUC)?

Yeah, it's 13Mhz.Clock setting from board would be good to have though
Currently there is only one board AM3517EVM.
  
> > +/**
> > + * musb_platform_enable - enable interrupts
> > + */
> > +void musb_platform_enable(struct musb *musb)
> > +{
> > +	void __iomem *reg_base = musb->ctrl_base;
> > +	u32 epmask, coremask;
> > +
> > +	/* Workaround: setup IRQs through both register sets. */
> > +	epmask = ((musb->epmask & AM3517_TX_EP_MASK) << USB_INTR_TX_SHIFT) |
> > +	       ((musb->epmask & AM3517_RX_EP_MASK) << USB_INTR_RX_SHIFT);
> > +	coremask = (0x01ff << USB_INTR_USB_SHIFT);
> > +
> > +	musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
> > +	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, coremask);
> >
> 
>    Hm, and I thought all CPPI 4.1 based controllers have the same
> register layout... alas, I was wrong.

There are changes as AM3517 supports 15Rx/Tx endpoints.

> 
> > +static int vbus_state = -1;
> >
> [...]
> > +static void am3517_source_power(struct musb *musb, int is_on, int
> immediate)
> > +{
> > +	if (is_on)
> > +		is_on = 1;
> > +
> > +	if (vbus_state == is_on)
> > +		return;
> > +	vbus_state = is_on;
> > +}
> > +
> >
> 
>    Without the real GPIOs to manipulate, I don't understand the purpose
> of this function...

Correct, this function can be removed.

> 
> > +static struct timer_list otg_workaround;
> > +
> > +static void otg_timer(unsigned long _musb)
> > +{
> > +	struct musb		*musb = (void *)_musb;
> > +	void __iomem		*mregs = musb->mregs;
> > +	u8			devctl;
> > +	unsigned long		flags;
> > +
> > +	/* We poll because AM3517's won't expose several OTG-critical
> > +	* status change events (from the transceiver) otherwise.
> >
> 
>    Need one more space before *...

Right.

> 
> > +	case OTG_STATE_A_WAIT_VFALL:
> > +		/*
> > +		 * Wait till VBUS falls below SessionEnd (~0.2 V); the 1.3
> > +		 * RTL seems to mis-handle session "start" otherwise (or in
> > +		 * our case "recover"), in routine "VBUS was valid by the time
> > +		 * VBUSERR got reported during enumeration" cases.
> > +		 */
> >
> 
>    I wonder if all this still true for RTL 1.8 on which DA8xx (and
> probably AM3517) MUSB is based...

Need to check on this..though I didn't see any issue in my testing.

> 
> > +void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
> > +{
> >
> 
>    I wonder how DaVinci gets about without musb_platfrom_try_idle()...

Hmm..
> 
> > +static irqreturn_t am3517_interrupt(int irq, void *hci)
> > +{
> 
> > +		/* NOTE: this must complete power-on within 100 ms. */
> > +		am3517_source_power(musb, drvvbus, 0);
> >
> 
>    This call is effectively a NOP.

Yes and so should be removed.

> 
> > +	if (musb->int_tx || musb->int_rx || musb->int_usb) {
> > +		irqreturn_t mret;
> > +
> > +		mret = musb_interrupt(musb);
> > +		if (mret == IRQ_HANDLED)
> > +			ret = IRQ_HANDLED;
> >
> 
>    Not sure why you didn't like ret |= musb_interrupt(musb)...

Need to verify/clean it. I remember, was getting some issue initially
On this path.

> 
> > +	if (ret != IRQ_HANDLED) {
> > +		if (epintr || usbintr)
> > +			/*
> > +			 * We sometimes get unhandled IRQs in the peripheral
> > +			 * mode from EP0 and SOF...
> > +			 */
> > +			DBG(2, "Unhandled USB IRQ %08x-%08x\n",
> > +					 epintr, usbintr);
> >
> 
>    This check shouldn't be needed any more -- EP0 spurious interrupts
> have been all chased down...

Ok fine.
> 
> > +		else if (printk_ratelimit())
> > +			/*
> > +			 * We've seen series of spurious interrupts in the
> > +			 * peripheral mode after USB reset and then after some
> > +			 * time a real interrupt storm starting...
> > +			 */
> > +			DBG(2, "Spurious IRQ\n");
> >
> 
>    Those turned out to be interrupts caused by CPPI 4.1 descriptor
> starvation (for which the controller didn't even have an interrupt bit).
> I still haven't dealt with them...

and.. AM3517 has got a bit to disable them, anyways this patch currently
supports PIO only so this check can be removed also.

> 
> > +	}
> > +	return ret;
> > +}
> > +
> > +int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
> > +{
> > +	WARNING("FIXME: %s not implemented\n", __func__);
> > +	return -EIO;
> >
> 
>    Could be implemented using CONF2_OTGMODE...

Ok fine.

> 
> > +int __init musb_platform_init(struct musb *musb)
> > +{
> > +	void __iomem *reg_base = musb->ctrl_base;
> > +	struct clk              *otg_fck;
> > +	u32 rev, lvl_intr, sw_reset;
> > +
> > +	usb_nop_xceiv_register();
> > +
> > +	musb->xceiv = otg_get_transceiver();
> > +	if (!musb->xceiv)
> > +		return -ENODEV;
> > +
> > +	/* Mentor is at offset of 0x400 in AM3517 */
> > +	musb->mregs += USB_MENTOR_CORE_OFFSET;
> > +
> > +	/* musb->clock is already set from board/arch files */
> > +	if (IS_ERR(musb->clock))
> > +		return PTR_ERR(musb->clock);
> >
> 
>   This is checked by musb_core.c now, no need to duplicate...

Ok fine.

> 
> > +	if (musb->set_clock)
> > +		musb->set_clock(musb->clock, 1);
> >
> 
>    musb->set_clock() is about to be dropped...

So there is 'else' part.
> 
> > +	else
> > +		clk_enable(musb->clock);
> > +
> > +	DBG(2, "usbotg_ck=%lud\n", clk_get_rate(musb->clock));
> >
> 
>    I'd put an empty line after that DBG() rather than before.
Ok fine.

> 
> > +	otg_fck = clk_get(musb->controller, "fck");
> > +	clk_enable(otg_fck);
> >
> 
>    Oh, it needs two clocks... Another argument against Felipe dropping
> plat->clock. :-)

..

> 
> > +
> > +	DBG(2, "usbotg_phy_ck=%lud\n", clk_get_rate(otg_fck));
> >
> 
>    Same about empty line here...
> 
> > +	am3517_source_power(musb, 0, 1);
> >
> 
>    Effective NOP...

So need to remove.

> 
> > +	/* Start the on-chip PHY and its PLL. */
> > +	phy_on();
> > +
> > +	msleep(15);
> >
> 
>    5 ms is not enough?

Need to test and correct.

> 
> > +	musb->a_wait_bcon = A_WAIT_BCON_TIMEOUT;
> >
> 
>    Hm... that line kept causing a stream of kernel messages for me,
> until I removed it. Doesn't it for you?

No I didn't get any error messages.. what messages were you getting ?

> 
> > diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
> > index 98fd5b6..f8efe00 100644
> > --- a/drivers/usb/musb/musb_core.c
> > +++ b/drivers/usb/musb/musb_core.c
> > @@ -982,7 +982,8 @@ static void musb_shutdown(struct platform_device
> *pdev)
> >   * more than selecting one of a bunch of predefined configurations.
> >   */
> >  #if defined(CONFIG_USB_TUSB6010) || \
> > -	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
> > +	defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
> > +	defined(CONFIG_MACH_OMAP3517EVM)
> >
> 
>    Isn't that dependency already covered by CONFIG_ARCH_OMAP3? Or else I
> don't see you adding your #ifdef around musb_platfrom_try_idle()
> declaration...

Right..this can be removed.

> +int musb_platform_exit(struct musb *musb) {
>   
[...]
> +	phy_off();
> +
> +	usb_nop_xceiv_unregister();
> +
> +	return 0;
>   

>>   You forgot the calls to clk_disable() for both your clocks...

Ok fine..need to correct.

Thanks,
Ajay
> 
> WBR, Sergei

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] musb: add musb support for AM35x
  2010-03-15  5:10       ` Gupta, Ajay Kumar
@ 2010-03-26 19:29         ` Sergei Shtylyov
  0 siblings, 0 replies; 6+ messages in thread
From: Sergei Shtylyov @ 2010-03-26 19:29 UTC (permalink / raw)
  To: Gupta, Ajay Kumar
  Cc: linux-usb@vger.kernel.org, linux-omap@vger.kernel.org,
	Felipe Balbi

Gupta, Ajay Kumar wrote:

>>> AM35x has musb interface and uses CPPI4.1 DMA engine.
>>> Current patch supports only PIO mode and there are on-going
>>> discussions on location of CPPI4.1 DMA.
>>>
>>> Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
>>>  	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
>>> @@ -140,7 +140,7 @@ config USB_MUSB_HDRC_HCD
>>>  config MUSB_PIO_ONLY
>>>  	bool 'Disable DMA (always use PIO)'
>>>  	depends on USB_MUSB_HDRC
>>> -	default y if USB_TUSB6010
>>> +	default USB_TUSB6010 || MACH_OMAP3517EVM
>>>  	help
>>>  	  All data is copied between memory and FIFO by the CPU.
>>>  	  DMA controllers are ignored.
>>> diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
>>> index 85710cc..9263033 100644
>>> --- a/drivers/usb/musb/Makefile
>>> +++ b/drivers/usb/musb/Makefile
>>> @@ -19,7 +19,11 @@ ifeq ($(CONFIG_ARCH_OMAP2430),y)
>>>  endif
>>>
>>>  ifeq ($(CONFIG_ARCH_OMAP3430),y)
>>> +   ifeq ($(CONFIG_MACH_OMAP3517EVM),y)
>>> +	musb_hdrc-objs  += am3517.o
>>>
>>>       
>>    Isn't there some ARCH-level option for AM3517 SoC? Depending on the
>> board type doesn't really scale well...
>>     
>
> AM3517 is actually based on OMAP3 but musb is different. Unfortunately there
> is no seperate *_ARCH_* defines for AM3517 alone.
>   

   I would really consider adding such... in the current situation the 
thing won't scale with addition of some new AM35x boards.

>>> +static inline void phy_on(void)
>>> +{
>>> +	u32 devconf2;
>>> +
>>> +	/*
>>> +	 * Start the on-chip PHY and its PLL.
>>> +	 */
>>> +	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
>>> +
>>> +	devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN |
>>> +			CONF2_OTGMODE | CONF2_REFFREQ | CONF2_PHY_GPIOMODE);
>>>
>>>       
>>    Shouldn't you manipulate CONF2_OTGMODE in the board code instead? I
>> suspect value of 0 doesn't fit the host-only configuration (without
>> cable connected, MUSB will think it's a B-device, and the driver will
>> fail to initialize IIRC).
>>     

   It will fail to power the port to be precise, so that when you 
finally connect a device, it won't get detected. Note that the comments 
in musb_core.c twice say that the driver expects ID pin to be *forcibly 
grounded* for the host-only mode while CONF2_OTGMODE's value of 0 will 
leave it floating.

> I didn't see any issue in Host/Device only and OTG mode configurations
> On AM3517? Did you see any issue on DA8xx?
>   

   Certainly still seeing it with OTGMODE=0 setting in the host mode -- 
see above.

>>> +/**
>>> + * musb_platform_enable - enable interrupts
>>> + */
>>> +void musb_platform_enable(struct musb *musb)
>>> +{
>>> +	void __iomem *reg_base = musb->ctrl_base;
>>> +	u32 epmask, coremask;
>>> +
>>> +	/* Workaround: setup IRQs through both register sets. */
>>> +	epmask = ((musb->epmask & AM3517_TX_EP_MASK) << USB_INTR_TX_SHIFT) |
>>> +	       ((musb->epmask & AM3517_RX_EP_MASK) << USB_INTR_RX_SHIFT);
>>> +	coremask = (0x01ff << USB_INTR_USB_SHIFT);
>>> +
>>> +	musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
>>> +	musb_writel(reg_base, CORE_INTR_MASK_SET_REG, coremask);
>>>
>>>       
>>    Hm, and I thought all CPPI 4.1 based controllers have the same
>> register layout... alas, I was wrong.
>>     
>
> There are changes as AM3517 supports 15Rx/Tx endpoints.
>   

   Yeah, I need to accomodate cppi41_dma.c to the changes by 
externalizing the code accessing the acceleration registers...

>>> +	case OTG_STATE_A_WAIT_VFALL:
>>> +		/*
>>> +		 * Wait till VBUS falls below SessionEnd (~0.2 V); the 1.3
>>> +		 * RTL seems to mis-handle session "start" otherwise (or in
>>> +		 * our case "recover"), in routine "VBUS was valid by the time
>>> +		 * VBUSERR got reported during enumeration" cases.
>>> +		 */
>>>
>>>       
>>    I wonder if all this still true for RTL 1.8 on which DA8xx (and
>> probably AM3517) MUSB is based...
>>     
>
> Need to check on this..though I didn't see any issue in my testing.
>   

   There should be no issues AFAIU, just the code can be made shorter I 
guess...

>>> +void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
>>> +{
>>>
>>>       
>>    I wonder how DaVinci gets about without musb_platfrom_try_idle()...
>>     
>
> Hmm..
>   

   davinci.c should also define musb_platfrom_try_idle() AFAIU... it 
should be no different from DA8xx in this respect.

>>> +	if (ret != IRQ_HANDLED) {
>>> +		if (epintr || usbintr)
>>> +			/*
>>> +			 * We sometimes get unhandled IRQs in the peripheral
>>> +			 * mode from EP0 and SOF...
>>> +			 */
>>> +			DBG(2, "Unhandled USB IRQ %08x-%08x\n",
>>> +					 epintr, usbintr);
>>>
>>>       
>>    This check shouldn't be needed any more -- EP0 spurious interrupts
>> have been all chased down...
>>     
>
> Ok fine.
>   

   However, I seem to have found a new case of unhandled interrupts 
today: when I disconnect a device, all I get is this message:

da8xx_interrupt 405: Unhandled USB IRQ 00280000

The driver failed to sense the disconnect, it's only reported when I 
re-inserted a device... that's something new. Felipe, are you reading this?

>>> +	musb->a_wait_bcon = A_WAIT_BCON_TIMEOUT;
>>>
>>>       
>>    Hm... that line kept causing a stream of kernel messages for me,
>> until I removed it. Doesn't it for you?
>>     
>
> No I didn't get any error messages.. what messages were you getting ?
>   

   Cannot reproduce them anymore and don't remember which message it was 
-- perhaps this:

musb_bus_suspend 2221: trying to suspend as a_wait_vrise is_active=1

Then it probably got fixed by:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=89368d3d11a5b2eff83ad8e752be67f77a372bad

Look at the below commit however -- it removed such code from omap2430.c:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=f7f9d63eac12b345d6243d1d608b7944a05be921

>> +int musb_platform_exit(struct musb *musb) {  
>>     
> [...]
>   
>> +	phy_off();
>> +
>> +	usb_nop_xceiv_unregister();
>> +
>> +	return 0;  
>>     
>>>   You forgot the calls to clk_disable() for both your clocks...
>>>       

   ... and clk_put() call for the functional clock.

> Ok fine..need to correct.
>
> Thanks,
> Ajay
WBR, Sergei



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-03-26 19:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-24 13:18 [PATCH 1/2] musb: add musb support for AM35x Ajay Kumar Gupta
     [not found] ` <1267017527-17591-1-git-send-email-ajay.gupta-l0cyMroinI0@public.gmane.org>
2010-02-24 13:18   ` [PATCH 2/2] AM35x: musb: Workaround for fifo read issue Ajay Kumar Gupta
2010-03-12 14:56   ` [PATCH 1/2] musb: add musb support for AM35x Sergei Shtylyov
     [not found]     ` <4B9A560B.7010908-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
2010-03-15  5:10       ` Gupta, Ajay Kumar
2010-03-26 19:29         ` Sergei Shtylyov
2010-03-12 15:04   ` Sergei Shtylyov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox