avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
34
u-boot/drivers/usb/musb-new/Kconfig
Normal file
34
u-boot/drivers/usb/musb-new/Kconfig
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# MUSB Controller Driver
|
||||
#
|
||||
comment "MUSB Controller Driver"
|
||||
|
||||
config USB_MUSB_HOST
|
||||
bool "MUSB host mode support"
|
||||
help
|
||||
Enables the MUSB USB dual-role controller in host mode.
|
||||
|
||||
config USB_MUSB_GADGET
|
||||
bool "MUSB gadget mode support"
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
Enables the MUSB USB dual-role controller in gadget mode.
|
||||
|
||||
if USB_MUSB_HOST || USB_MUSB_GADGET
|
||||
|
||||
config USB_MUSB_PIC32
|
||||
bool "Enable Microchip PIC32 DRC USB controller"
|
||||
depends on DM_USB && MACH_PIC32
|
||||
help
|
||||
Say y to enable PIC32 USB DRC controller support
|
||||
if it is available on your Microchip PIC32 platform.
|
||||
|
||||
config USB_MUSB_SUNXI
|
||||
bool "Enable sunxi OTG / DRC USB controller"
|
||||
depends on ARCH_SUNXI
|
||||
default y
|
||||
---help---
|
||||
Say y here to enable support for the sunxi OTG / DRC USB controller
|
||||
used on almost all sunxi boards.
|
||||
|
||||
endif
|
||||
18
u-boot/drivers/usb/musb-new/Makefile
Normal file
18
u-boot/drivers/usb/musb-new/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# for USB OTG silicon based on Mentor Graphics INVENTRA designs
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_USB_MUSB_GADGET) += musb_gadget.o musb_gadget_ep0.o musb_core.o
|
||||
obj-$(CONFIG_USB_MUSB_GADGET) += musb_uboot.o
|
||||
obj-$(CONFIG_USB_MUSB_HOST) += musb_host.o musb_core.o musb_uboot.o
|
||||
obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
|
||||
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
|
||||
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
|
||||
obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
|
||||
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
|
||||
|
||||
ccflags-y := $(call cc-option,-Wno-unused-variable) \
|
||||
$(call cc-option,-Wno-unused-but-set-variable) \
|
||||
$(call cc-option,-Wno-unused-label)
|
||||
701
u-boot/drivers/usb/musb-new/am35x.c
Normal file
701
u-boot/drivers/usb/musb-new/am35x.c
Normal file
@@ -0,0 +1,701 @@
|
||||
/*
|
||||
* Texas Instruments AM35x "glue layer"
|
||||
*
|
||||
* Copyright (c) 2010, by Texas Instruments
|
||||
*
|
||||
* Based on the DA8xx "glue layer" code.
|
||||
* Copyright (c) 2008-2009, MontaVista Software, Inc. <source@mvista.com>
|
||||
*
|
||||
* This file is part of the Inventra Controller Driver for Linux.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <plat/usb.h>
|
||||
#else
|
||||
#include <common.h>
|
||||
#include <asm/omap_musb.h>
|
||||
#include "linux-compat.h"
|
||||
#endif
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
/*
|
||||
* AM35x specific definitions
|
||||
*/
|
||||
/* USB 2.0 OTG module registers */
|
||||
#define USB_REVISION_REG 0x00
|
||||
#define USB_CTRL_REG 0x04
|
||||
#define USB_STAT_REG 0x08
|
||||
#define USB_EMULATION_REG 0x0c
|
||||
/* 0x10 Reserved */
|
||||
#define USB_AUTOREQ_REG 0x14
|
||||
#define USB_SRP_FIX_TIME_REG 0x18
|
||||
#define USB_TEARDOWN_REG 0x1c
|
||||
#define EP_INTR_SRC_REG 0x20
|
||||
#define EP_INTR_SRC_SET_REG 0x24
|
||||
#define EP_INTR_SRC_CLEAR_REG 0x28
|
||||
#define EP_INTR_MASK_REG 0x2c
|
||||
#define EP_INTR_MASK_SET_REG 0x30
|
||||
#define EP_INTR_MASK_CLEAR_REG 0x34
|
||||
#define EP_INTR_SRC_MASKED_REG 0x38
|
||||
#define CORE_INTR_SRC_REG 0x40
|
||||
#define CORE_INTR_SRC_SET_REG 0x44
|
||||
#define CORE_INTR_SRC_CLEAR_REG 0x48
|
||||
#define CORE_INTR_MASK_REG 0x4c
|
||||
#define CORE_INTR_MASK_SET_REG 0x50
|
||||
#define CORE_INTR_MASK_CLEAR_REG 0x54
|
||||
#define CORE_INTR_SRC_MASKED_REG 0x58
|
||||
/* 0x5c Reserved */
|
||||
#define USB_END_OF_INTR_REG 0x60
|
||||
|
||||
/* Control register bits */
|
||||
#define AM35X_SOFT_RESET_MASK 1
|
||||
|
||||
/* USB interrupt register bits */
|
||||
#define AM35X_INTR_USB_SHIFT 16
|
||||
#define AM35X_INTR_USB_MASK (0x1ff << AM35X_INTR_USB_SHIFT)
|
||||
#define AM35X_INTR_DRVVBUS 0x100
|
||||
#define AM35X_INTR_RX_SHIFT 16
|
||||
#define AM35X_INTR_TX_SHIFT 0
|
||||
#define AM35X_TX_EP_MASK 0xffff /* EP0 + 15 Tx EPs */
|
||||
#define AM35X_RX_EP_MASK 0xfffe /* 15 Rx EPs */
|
||||
#define AM35X_TX_INTR_MASK (AM35X_TX_EP_MASK << AM35X_INTR_TX_SHIFT)
|
||||
#define AM35X_RX_INTR_MASK (AM35X_RX_EP_MASK << AM35X_INTR_RX_SHIFT)
|
||||
|
||||
#define USB_MENTOR_CORE_OFFSET 0x400
|
||||
|
||||
struct am35x_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct clk *phy_clk;
|
||||
struct clk *clk;
|
||||
};
|
||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
||||
|
||||
/*
|
||||
* am35x_musb_enable - enable interrupts
|
||||
*/
|
||||
#ifndef __UBOOT__
|
||||
static void am35x_musb_enable(struct musb *musb)
|
||||
#else
|
||||
static int am35x_musb_enable(struct musb *musb)
|
||||
#endif
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 epmask;
|
||||
|
||||
/* Workaround: setup IRQs through both register sets. */
|
||||
epmask = ((musb->epmask & AM35X_TX_EP_MASK) << AM35X_INTR_TX_SHIFT) |
|
||||
((musb->epmask & AM35X_RX_EP_MASK) << AM35X_INTR_RX_SHIFT);
|
||||
|
||||
musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
|
||||
musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK);
|
||||
|
||||
/* 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,
|
||||
AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
|
||||
#ifdef __UBOOT__
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* am35x_musb_disable - disable HDRC and flush interrupts
|
||||
*/
|
||||
static void am35x_musb_disable(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
|
||||
musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK);
|
||||
musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG,
|
||||
AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK);
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
||||
musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#define portstate(stmt) stmt
|
||||
|
||||
static void am35x_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
WARN_ON(is_on && is_peripheral_active(musb));
|
||||
}
|
||||
|
||||
#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 AM35x's won't expose several OTG-critical
|
||||
* status change events (from the transceiver) otherwise.
|
||||
*/
|
||||
devctl = musb_readb(mregs, MUSB_DEVCTL);
|
||||
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
|
||||
otg_state_string(musb->xceiv->state));
|
||||
|
||||
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:
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG,
|
||||
MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
|
||||
break;
|
||||
case OTG_STATE_B_IDLE:
|
||||
if (!is_peripheral_enabled(musb))
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void am35x_musb_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)) {
|
||||
dev_dbg(musb->controller, "%s active, deleting timer\n",
|
||||
otg_state_string(musb->xceiv->state));
|
||||
del_timer(&otg_workaround);
|
||||
last_timer = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
|
||||
dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
last_timer = timeout;
|
||||
|
||||
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
jiffies_to_msecs(timeout - jiffies));
|
||||
mod_timer(&otg_workaround, timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
struct usb_otg *otg = musb->xceiv->otg;
|
||||
#else
|
||||
struct omap_musb_board_data *data =
|
||||
(struct omap_musb_board_data *)musb->controller;
|
||||
#endif
|
||||
unsigned long flags;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 epintr, usbintr;
|
||||
|
||||
#ifdef __UBOOT__
|
||||
/*
|
||||
* It seems that on AM35X interrupt registers can be updated
|
||||
* before core registers. This confuses the code.
|
||||
* As a workaround add a small delay here.
|
||||
*/
|
||||
udelay(10);
|
||||
#endif
|
||||
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 & AM35X_RX_INTR_MASK) >> AM35X_INTR_RX_SHIFT;
|
||||
musb->int_tx =
|
||||
(epintr & AM35X_TX_INTR_MASK) >> AM35X_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 & AM35X_INTR_USB_MASK) >> AM35X_INTR_USB_SHIFT;
|
||||
}
|
||||
#ifndef __UBOOT__
|
||||
/*
|
||||
* DRVVBUS IRQs are the only proxy we have (a very poor one!) for
|
||||
* AM35x'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 & (AM35X_INTR_DRVVBUS << AM35X_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_HST_MODE(musb);
|
||||
otg->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);
|
||||
otg->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. */
|
||||
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
drvvbus ? "on" : "off",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
err ? " ERROR" : "",
|
||||
devctl);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (musb->int_tx || musb->int_rx || musb->int_usb)
|
||||
ret |= musb_interrupt(musb);
|
||||
|
||||
eoi:
|
||||
/* EOI needs to be written for the IRQ to be re-asserted. */
|
||||
if (ret == IRQ_HANDLED || epintr || usbintr) {
|
||||
/* clear level interrupt */
|
||||
if (data->clear_irq)
|
||||
data->clear_irq();
|
||||
/* write EOI */
|
||||
musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* Poll for ID change */
|
||||
if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
|
||||
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
|
||||
#endif
|
||||
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
int retval = 0;
|
||||
|
||||
if (data->set_mode)
|
||||
data->set_mode(musb_mode);
|
||||
else
|
||||
retval = -EIO;
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int am35x_musb_init(struct musb *musb)
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
#else
|
||||
struct omap_musb_board_data *data =
|
||||
(struct omap_musb_board_data *)musb->controller;
|
||||
#endif
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 rev;
|
||||
|
||||
musb->mregs += USB_MENTOR_CORE_OFFSET;
|
||||
|
||||
/* Returns zero if e.g. not clocked */
|
||||
rev = musb_readl(reg_base, USB_REVISION_REG);
|
||||
if (!rev)
|
||||
return -ENODEV;
|
||||
|
||||
#ifndef __UBOOT__
|
||||
usb_nop_xceiv_register();
|
||||
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(musb->xceiv))
|
||||
return -ENODEV;
|
||||
|
||||
if (is_host_enabled(musb))
|
||||
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
|
||||
#endif
|
||||
|
||||
/* Reset the musb */
|
||||
if (data->reset)
|
||||
data->reset();
|
||||
|
||||
/* Reset the controller */
|
||||
musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(1);
|
||||
|
||||
msleep(5);
|
||||
|
||||
musb->isr = am35x_musb_interrupt;
|
||||
|
||||
/* clear level interrupt */
|
||||
if (data->clear_irq)
|
||||
data->clear_irq();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am35x_musb_exit(struct musb *musb)
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
#else
|
||||
struct omap_musb_board_data *data =
|
||||
(struct omap_musb_board_data *)musb->controller;
|
||||
#endif
|
||||
|
||||
#ifndef __UBOOT__
|
||||
if (is_host_enabled(musb))
|
||||
del_timer_sync(&otg_workaround);
|
||||
#endif
|
||||
|
||||
/* Shutdown the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(0);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
usb_put_phy(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 remaining 1 to 3 byte or complete length if
|
||||
* unaligned address.
|
||||
*/
|
||||
if (len > 4) {
|
||||
for (i = 0; i < (len >> 2); i++) {
|
||||
*(u32 *) dst = musb_readl(fifo, 0);
|
||||
dst += 4;
|
||||
}
|
||||
len &= 0x03;
|
||||
}
|
||||
if (len > 0) {
|
||||
val = musb_readl(fifo, 0);
|
||||
memcpy(dst, &val, len);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static const struct musb_platform_ops am35x_ops = {
|
||||
#else
|
||||
const struct musb_platform_ops am35x_ops = {
|
||||
#endif
|
||||
.init = am35x_musb_init,
|
||||
.exit = am35x_musb_exit,
|
||||
|
||||
.enable = am35x_musb_enable,
|
||||
.disable = am35x_musb_disable,
|
||||
|
||||
#ifndef __UBOOT__
|
||||
.set_mode = am35x_musb_set_mode,
|
||||
.try_idle = am35x_musb_try_idle,
|
||||
|
||||
.set_vbus = am35x_musb_set_vbus,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static u64 am35x_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __devinit am35x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct am35x_glue *glue;
|
||||
|
||||
struct clk *phy_clk;
|
||||
struct clk *clk;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
phy_clk = clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(phy_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get PHY clock\n");
|
||||
ret = PTR_ERR(phy_clk);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
clk = clk_get(&pdev->dev, "ick");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err3;
|
||||
}
|
||||
|
||||
ret = clk_enable(phy_clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable PHY clock\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = clk_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &am35x_dmamask;
|
||||
musb->dev.coherent_dma_mask = am35x_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->phy_clk = phy_clk;
|
||||
glue->clk = clk;
|
||||
|
||||
pdata->platform_ops = &am35x_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err6:
|
||||
clk_disable(clk);
|
||||
|
||||
err5:
|
||||
clk_disable(phy_clk);
|
||||
|
||||
err4:
|
||||
clk_put(clk);
|
||||
|
||||
err3:
|
||||
clk_put(phy_clk);
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit am35x_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct am35x_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
clk_disable(glue->clk);
|
||||
clk_disable(glue->phy_clk);
|
||||
clk_put(glue->clk);
|
||||
clk_put(glue->phy_clk);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int am35x_suspend(struct device *dev)
|
||||
{
|
||||
struct am35x_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
|
||||
/* Shutdown the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(0);
|
||||
|
||||
clk_disable(glue->phy_clk);
|
||||
clk_disable(glue->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am35x_resume(struct device *dev)
|
||||
{
|
||||
struct am35x_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
int ret;
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(1);
|
||||
|
||||
ret = clk_enable(glue->phy_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable PHY clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_enable(glue->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops am35x_pm_ops = {
|
||||
.suspend = am35x_suspend,
|
||||
.resume = am35x_resume,
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS &am35x_pm_ops
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver am35x_driver = {
|
||||
.probe = am35x_probe,
|
||||
.remove = __devexit_p(am35x_remove),
|
||||
.driver = {
|
||||
.name = "musb-am35x",
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("AM35x MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init am35x_init(void)
|
||||
{
|
||||
return platform_driver_register(&am35x_driver);
|
||||
}
|
||||
module_init(am35x_init);
|
||||
|
||||
static void __exit am35x_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&am35x_driver);
|
||||
}
|
||||
module_exit(am35x_exit);
|
||||
#endif
|
||||
37
u-boot/drivers/usb/musb-new/linux-compat.h
Normal file
37
u-boot/drivers/usb/musb-new/linux-compat.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef __LINUX_COMPAT_H__
|
||||
#define __LINUX_COMPAT_H__
|
||||
|
||||
#include <malloc.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
#define pr_debug(fmt, args...) debug(fmt, ##args)
|
||||
|
||||
#define WARN(condition, fmt, args...) ({ \
|
||||
int ret_warn = !!condition; \
|
||||
if (ret_warn) \
|
||||
printf(fmt, ##args); \
|
||||
ret_warn; })
|
||||
|
||||
#define device_init_wakeup(dev, a) do {} while (0)
|
||||
|
||||
#define platform_data device_data
|
||||
|
||||
#ifndef wmb
|
||||
#define wmb() asm volatile ("" : : : "memory")
|
||||
#endif
|
||||
|
||||
#define msleep(a) udelay(a * 1000)
|
||||
|
||||
/*
|
||||
* Map U-Boot config options to Linux ones
|
||||
*/
|
||||
#ifdef CONFIG_OMAP34XX
|
||||
#define CONFIG_SOC_OMAP3430
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP4430
|
||||
#define CONFIG_ARCH_OMAP4
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_COMPAT_H__ */
|
||||
2493
u-boot/drivers/usb/musb-new/musb_core.c
Normal file
2493
u-boot/drivers/usb/musb-new/musb_core.c
Normal file
File diff suppressed because it is too large
Load Diff
617
u-boot/drivers/usb/musb-new/musb_core.h
Normal file
617
u-boot/drivers/usb/musb-new/musb_core.h
Normal file
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* MUSB OTG driver defines
|
||||
*
|
||||
* Copyright 2005 Mentor Graphics Corporation
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
* Copyright (C) 2006-2007 Nokia Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_CORE_H__
|
||||
#define __MUSB_CORE_H__
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#else
|
||||
#include <asm/errno.h>
|
||||
#endif
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/musb.h>
|
||||
|
||||
struct musb;
|
||||
struct musb_hw_ep;
|
||||
struct musb_ep;
|
||||
|
||||
/* Helper defines for struct musb->hwvers */
|
||||
#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
|
||||
#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
|
||||
#define MUSB_HWVERS_RC 0x8000
|
||||
#define MUSB_HWVERS_1300 0x52C
|
||||
#define MUSB_HWVERS_1400 0x590
|
||||
#define MUSB_HWVERS_1800 0x720
|
||||
#define MUSB_HWVERS_1900 0x784
|
||||
#define MUSB_HWVERS_2000 0x800
|
||||
|
||||
#include "musb_debug.h"
|
||||
#include "musb_dma.h"
|
||||
|
||||
#include "musb_io.h"
|
||||
#include "musb_regs.h"
|
||||
|
||||
#include "musb_gadget.h"
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/usb/hcd.h>
|
||||
#endif
|
||||
#include "musb_host.h"
|
||||
|
||||
#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST)
|
||||
#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL)
|
||||
#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG)
|
||||
|
||||
/* NOTE: otg and peripheral-only state machines start at B_IDLE.
|
||||
* OTG or host-only go to A_IDLE when ID is sensed.
|
||||
*/
|
||||
#define is_peripheral_active(m) (!(m)->is_host)
|
||||
#define is_host_active(m) ((m)->is_host)
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/fs.h>
|
||||
#define MUSB_CONFIG_PROC_FS
|
||||
#endif
|
||||
|
||||
/****************************** PERIPHERAL ROLE *****************************/
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#define is_peripheral_capable() (1)
|
||||
#else
|
||||
#ifdef CONFIG_USB_MUSB_GADGET
|
||||
#define is_peripheral_capable() (1)
|
||||
#else
|
||||
#define is_peripheral_capable() (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern irqreturn_t musb_g_ep0_irq(struct musb *);
|
||||
extern void musb_g_tx(struct musb *, u8);
|
||||
extern void musb_g_rx(struct musb *, u8);
|
||||
extern void musb_g_reset(struct musb *);
|
||||
extern void musb_g_suspend(struct musb *);
|
||||
extern void musb_g_resume(struct musb *);
|
||||
extern void musb_g_wakeup(struct musb *);
|
||||
extern void musb_g_disconnect(struct musb *);
|
||||
|
||||
/****************************** HOST ROLE ***********************************/
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#define is_host_capable() (1)
|
||||
#else
|
||||
#ifdef CONFIG_USB_MUSB_HOST
|
||||
#define is_host_capable() (1)
|
||||
#else
|
||||
#define is_host_capable() (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern irqreturn_t musb_h_ep0_irq(struct musb *);
|
||||
extern void musb_host_tx(struct musb *, u8);
|
||||
extern void musb_host_rx(struct musb *, u8);
|
||||
|
||||
/****************************** CONSTANTS ********************************/
|
||||
|
||||
#ifndef MUSB_C_NUM_EPS
|
||||
#define MUSB_C_NUM_EPS ((u8)16)
|
||||
#endif
|
||||
|
||||
#ifndef MUSB_MAX_END0_PACKET
|
||||
#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE)
|
||||
#endif
|
||||
|
||||
/* host side ep0 states */
|
||||
enum musb_h_ep0_state {
|
||||
MUSB_EP0_IDLE,
|
||||
MUSB_EP0_START, /* expect ack of setup */
|
||||
MUSB_EP0_IN, /* expect IN DATA */
|
||||
MUSB_EP0_OUT, /* expect ack of OUT DATA */
|
||||
MUSB_EP0_STATUS, /* expect ack of STATUS */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* peripheral side ep0 states */
|
||||
enum musb_g_ep0_state {
|
||||
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) */
|
||||
MUSB_EP0_STAGE_STATUSOUT, /* (after IN data) */
|
||||
MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* 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 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 ********************************/
|
||||
|
||||
/* Endpoint registers (other than dynfifo setup) can be accessed either
|
||||
* directly with the "flat" model, or after setting up an index register.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \
|
||||
|| defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \
|
||||
|| defined(CONFIG_ARCH_OMAP4)
|
||||
/* REVISIT indexed access seemed to
|
||||
* misbehave (on DaVinci) for at least peripheral IN ...
|
||||
*/
|
||||
#define MUSB_FLAT_REG
|
||||
#endif
|
||||
|
||||
/* TUSB mapping: "flat" plus ep0 special cases */
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
|
||||
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
|
||||
#define musb_ep_select(_mbase, _epnum) \
|
||||
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
|
||||
#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
|
||||
|
||||
/* "flat" mapping: each endpoint has its own i/o address */
|
||||
#elif defined(MUSB_FLAT_REG)
|
||||
#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)), ((void)(_epnum)))
|
||||
#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET
|
||||
|
||||
/* "indexed" mapping: INDEX register controls register bank select */
|
||||
#else
|
||||
#define musb_ep_select(_mbase, _epnum) \
|
||||
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
|
||||
#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET
|
||||
#endif
|
||||
|
||||
/****************************** FUNCTIONS ********************************/
|
||||
|
||||
#define MUSB_HST_MODE(_musb)\
|
||||
{ (_musb)->is_host = true; }
|
||||
#define MUSB_DEV_MODE(_musb) \
|
||||
{ (_musb)->is_host = false; }
|
||||
|
||||
#define test_devctl_hst_mode(_x) \
|
||||
(musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM)
|
||||
|
||||
#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral")
|
||||
|
||||
/******************************** TYPES *************************************/
|
||||
|
||||
/**
|
||||
* struct musb_platform_ops - Operations passed to musb_core by HW glue layer
|
||||
* @init: turns on clocks, sets up platform-specific registers, etc
|
||||
* @exit: undoes @init
|
||||
* @set_mode: forcefully changes operating mode
|
||||
* @try_ilde: tries to idle the IP
|
||||
* @vbus_status: returns vbus status if possible
|
||||
* @set_vbus: forces vbus status
|
||||
* @adjust_channel_params: pre check for standard dma channel_program func
|
||||
*/
|
||||
struct musb_platform_ops {
|
||||
int (*init)(struct musb *musb);
|
||||
int (*exit)(struct musb *musb);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
void (*enable)(struct musb *musb);
|
||||
#else
|
||||
int (*enable)(struct musb *musb);
|
||||
#endif
|
||||
void (*disable)(struct musb *musb);
|
||||
|
||||
int (*set_mode)(struct musb *musb, u8 mode);
|
||||
void (*try_idle)(struct musb *musb, unsigned long timeout);
|
||||
|
||||
int (*vbus_status)(struct musb *musb);
|
||||
void (*set_vbus)(struct musb *musb, int on);
|
||||
|
||||
int (*adjust_channel_params)(struct dma_channel *channel,
|
||||
u16 packet_sz, u8 *mode,
|
||||
dma_addr_t *dma_addr, u32 *len);
|
||||
};
|
||||
|
||||
/*
|
||||
* struct musb_hw_ep - endpoint hardware (bidirectional)
|
||||
*
|
||||
* Ordered slightly for better cacheline locality.
|
||||
*/
|
||||
struct musb_hw_ep {
|
||||
struct musb *musb;
|
||||
void __iomem *fifo;
|
||||
void __iomem *regs;
|
||||
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
|
||||
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
|
||||
void __iomem *conf;
|
||||
#endif
|
||||
|
||||
/* index in musb->endpoints[] */
|
||||
u8 epnum;
|
||||
|
||||
/* hardware configuration, possibly dynamic */
|
||||
bool is_shared_fifo;
|
||||
bool tx_double_buffered;
|
||||
bool rx_double_buffered;
|
||||
u16 max_packet_sz_tx;
|
||||
u16 max_packet_sz_rx;
|
||||
|
||||
struct dma_channel *tx_channel;
|
||||
struct dma_channel *rx_channel;
|
||||
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
|
||||
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
|
||||
/* TUSB has "asynchronous" and "synchronous" dma modes */
|
||||
dma_addr_t fifo_async;
|
||||
dma_addr_t fifo_sync;
|
||||
void __iomem *fifo_sync_va;
|
||||
#endif
|
||||
|
||||
void __iomem *target_regs;
|
||||
|
||||
/* currently scheduled peripheral endpoint */
|
||||
struct musb_qh *in_qh;
|
||||
struct musb_qh *out_qh;
|
||||
|
||||
u8 rx_reinit;
|
||||
u8 tx_reinit;
|
||||
|
||||
/* peripheral side */
|
||||
struct musb_ep ep_in; /* TX */
|
||||
struct musb_ep ep_out; /* RX */
|
||||
};
|
||||
|
||||
static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep)
|
||||
{
|
||||
return next_request(&hw_ep->ep_in);
|
||||
}
|
||||
|
||||
static inline struct musb_request *next_out_request(struct musb_hw_ep *hw_ep)
|
||||
{
|
||||
return next_request(&hw_ep->ep_out);
|
||||
}
|
||||
|
||||
struct musb_csr_regs {
|
||||
/* FIFO registers */
|
||||
u16 txmaxp, txcsr, rxmaxp, rxcsr;
|
||||
u16 rxfifoadd, txfifoadd;
|
||||
u8 txtype, txinterval, rxtype, rxinterval;
|
||||
u8 rxfifosz, txfifosz;
|
||||
u8 txfunaddr, txhubaddr, txhubport;
|
||||
u8 rxfunaddr, rxhubaddr, rxhubport;
|
||||
};
|
||||
|
||||
struct musb_context_registers {
|
||||
|
||||
u8 power;
|
||||
u16 intrtxe, intrrxe;
|
||||
u8 intrusbe;
|
||||
u16 frame;
|
||||
u8 index, testmode;
|
||||
|
||||
u8 devctl, busctl, misc;
|
||||
u32 otg_interfsel;
|
||||
|
||||
struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
|
||||
};
|
||||
|
||||
/*
|
||||
* struct musb - Driver instance data.
|
||||
*/
|
||||
struct musb {
|
||||
/* device lock */
|
||||
spinlock_t lock;
|
||||
|
||||
const struct musb_platform_ops *ops;
|
||||
struct musb_context_registers context;
|
||||
|
||||
irqreturn_t (*isr)(int, void *);
|
||||
struct work_struct irq_work;
|
||||
u16 hwvers;
|
||||
|
||||
/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
|
||||
#define MUSB_PORT_STAT_RESUME (1 << 31)
|
||||
|
||||
u32 port1_status;
|
||||
|
||||
unsigned long rh_timer;
|
||||
|
||||
enum musb_h_ep0_state ep0_stage;
|
||||
|
||||
/* bulk traffic normally dedicates endpoint hardware, and each
|
||||
* direction has its own ring of host side endpoints.
|
||||
* we try to progress the transfer at the head of each endpoint's
|
||||
* queue until it completes or NAKs too much; then we try the next
|
||||
* endpoint.
|
||||
*/
|
||||
struct musb_hw_ep *bulk_ep;
|
||||
|
||||
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;
|
||||
struct notifier_block nb;
|
||||
|
||||
struct dma_controller *dma_controller;
|
||||
|
||||
struct device *controller;
|
||||
void __iomem *ctrl_base;
|
||||
void __iomem *mregs;
|
||||
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
|
||||
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
|
||||
dma_addr_t async;
|
||||
dma_addr_t sync;
|
||||
void __iomem *sync_va;
|
||||
#endif
|
||||
|
||||
/* passed down from chip/board specific irq handlers */
|
||||
u8 int_usb;
|
||||
u16 int_rx;
|
||||
u16 int_tx;
|
||||
|
||||
struct usb_phy *xceiv;
|
||||
|
||||
int nIrq;
|
||||
unsigned irq_wake:1;
|
||||
|
||||
struct musb_hw_ep endpoints[MUSB_C_NUM_EPS];
|
||||
#define control_ep endpoints
|
||||
|
||||
#define VBUSERR_RETRY_COUNT 3
|
||||
u16 vbuserr_retry;
|
||||
u16 epmask;
|
||||
u8 nr_endpoints;
|
||||
|
||||
u8 board_mode; /* enum musb_mode */
|
||||
int (*board_set_power)(int state);
|
||||
|
||||
u8 min_power; /* vbus for periph, in mA/2 */
|
||||
|
||||
bool is_host;
|
||||
|
||||
int a_wait_bcon; /* VBUS timeout in msecs */
|
||||
unsigned long idle_timeout; /* Next timeout in jiffies */
|
||||
|
||||
/* active means connected and not suspended */
|
||||
unsigned is_active:1;
|
||||
|
||||
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? */
|
||||
unsigned dyn_fifo:1; /* dynamic FIFO supported? */
|
||||
|
||||
unsigned bulk_split:1;
|
||||
#define can_bulk_split(musb,type) \
|
||||
(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
|
||||
|
||||
unsigned bulk_combine:1;
|
||||
#define can_bulk_combine(musb,type) \
|
||||
(((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
|
||||
|
||||
/* is_suspended means USB B_PERIPHERAL suspend */
|
||||
unsigned is_suspended:1;
|
||||
|
||||
/* may_wakeup means remote wakeup is enabled */
|
||||
unsigned may_wakeup:1;
|
||||
|
||||
/* is_self_powered is reported in device status and the
|
||||
* config descriptor. is_bus_powered means B_PERIPHERAL
|
||||
* draws some VBUS current; both can be true.
|
||||
*/
|
||||
unsigned is_self_powered:1;
|
||||
unsigned is_bus_powered:1;
|
||||
|
||||
unsigned set_address:1;
|
||||
unsigned test_mode:1;
|
||||
unsigned softconnect:1;
|
||||
|
||||
u8 address;
|
||||
u8 test_mode_nr;
|
||||
u16 ackpend; /* ep0 */
|
||||
enum musb_g_ep0_state ep0_state;
|
||||
struct usb_gadget g; /* the gadget */
|
||||
struct usb_gadget_driver *gadget_driver; /* its driver */
|
||||
|
||||
/*
|
||||
* FIXME: Remove this flag.
|
||||
*
|
||||
* This is only added to allow Blackfin to work
|
||||
* with current driver. For some unknown reason
|
||||
* Blackfin doesn't work with double buffering
|
||||
* and that's enabled by default.
|
||||
*
|
||||
* We added this flag to forcefully disable double
|
||||
* buffering until we get it working.
|
||||
*/
|
||||
unsigned double_buffer_not_ok:1;
|
||||
|
||||
struct musb_hdrc_config *config;
|
||||
|
||||
#ifdef MUSB_CONFIG_PROC_FS
|
||||
struct proc_dir_entry *proc_entry;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct musb *gadget_to_musb(struct usb_gadget *g)
|
||||
{
|
||||
return container_of(g, struct musb, g);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLACKFIN
|
||||
static inline int musb_read_fifosize(struct musb *musb,
|
||||
struct musb_hw_ep *hw_ep, u8 epnum)
|
||||
{
|
||||
musb->nr_endpoints++;
|
||||
musb->epmask |= (1 << epnum);
|
||||
|
||||
if (epnum < 5) {
|
||||
hw_ep->max_packet_sz_tx = 128;
|
||||
hw_ep->max_packet_sz_rx = 128;
|
||||
} else {
|
||||
hw_ep->max_packet_sz_tx = 1024;
|
||||
hw_ep->max_packet_sz_rx = 1024;
|
||||
}
|
||||
hw_ep->is_shared_fifo = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void musb_configure_ep0(struct musb *musb)
|
||||
{
|
||||
musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
|
||||
musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
|
||||
musb->endpoints[0].is_shared_fifo = true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int musb_read_fifosize(struct musb *musb,
|
||||
struct musb_hw_ep *hw_ep, u8 epnum)
|
||||
{
|
||||
void *mbase = musb->mregs;
|
||||
u8 reg = 0;
|
||||
|
||||
/* read from core using indexed model */
|
||||
reg = musb_readb(mbase, MUSB_EP_OFFSET(epnum, MUSB_FIFOSIZE));
|
||||
/* 0's returned when no more endpoints */
|
||||
if (!reg)
|
||||
return -ENODEV;
|
||||
|
||||
musb->nr_endpoints++;
|
||||
musb->epmask |= (1 << epnum);
|
||||
|
||||
hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f);
|
||||
|
||||
/* shared TX/RX FIFO? */
|
||||
if ((reg & 0xf0) == 0xf0) {
|
||||
hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx;
|
||||
hw_ep->is_shared_fifo = true;
|
||||
return 0;
|
||||
} else {
|
||||
hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
|
||||
hw_ep->is_shared_fifo = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void musb_configure_ep0(struct musb *musb)
|
||||
{
|
||||
musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
|
||||
musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
|
||||
musb->endpoints[0].is_shared_fifo = true;
|
||||
}
|
||||
#endif /* CONFIG_BLACKFIN */
|
||||
|
||||
|
||||
/***************************** Glue it together *****************************/
|
||||
|
||||
extern const char musb_driver_name[];
|
||||
|
||||
#ifndef __UBOOT__
|
||||
extern void musb_start(struct musb *musb);
|
||||
#else
|
||||
extern int musb_start(struct musb *musb);
|
||||
#endif
|
||||
extern void musb_stop(struct musb *musb);
|
||||
|
||||
extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
|
||||
extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);
|
||||
|
||||
extern void musb_load_testpacket(struct musb *);
|
||||
|
||||
extern irqreturn_t musb_interrupt(struct musb *);
|
||||
|
||||
extern void musb_hnp_stop(struct musb *musb);
|
||||
|
||||
static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
if (musb->ops->set_vbus)
|
||||
musb->ops->set_vbus(musb, is_on);
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static inline void musb_platform_enable(struct musb *musb)
|
||||
{
|
||||
if (musb->ops->enable)
|
||||
musb->ops->enable(musb);
|
||||
}
|
||||
#else
|
||||
static inline int musb_platform_enable(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->enable)
|
||||
return 0;
|
||||
|
||||
return musb->ops->enable(musb);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void musb_platform_disable(struct musb *musb)
|
||||
{
|
||||
if (musb->ops->disable)
|
||||
musb->ops->disable(musb);
|
||||
}
|
||||
|
||||
static inline int musb_platform_set_mode(struct musb *musb, u8 mode)
|
||||
{
|
||||
if (!musb->ops->set_mode)
|
||||
return 0;
|
||||
|
||||
return musb->ops->set_mode(musb, mode);
|
||||
}
|
||||
|
||||
static inline void musb_platform_try_idle(struct musb *musb,
|
||||
unsigned long timeout)
|
||||
{
|
||||
if (musb->ops->try_idle)
|
||||
musb->ops->try_idle(musb, timeout);
|
||||
}
|
||||
|
||||
static inline int musb_platform_get_vbus_status(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->vbus_status)
|
||||
return 0;
|
||||
|
||||
return musb->ops->vbus_status(musb);
|
||||
}
|
||||
|
||||
static inline int musb_platform_init(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->init)
|
||||
return -EINVAL;
|
||||
|
||||
return musb->ops->init(musb);
|
||||
}
|
||||
|
||||
static inline int musb_platform_exit(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->exit)
|
||||
return -EINVAL;
|
||||
|
||||
return musb->ops->exit(musb);
|
||||
}
|
||||
|
||||
#ifdef __UBOOT__
|
||||
struct musb *
|
||||
musb_init_controller(struct musb_hdrc_platform_data *plat, struct device *dev,
|
||||
void *ctrl);
|
||||
#endif
|
||||
#endif /* __MUSB_CORE_H__ */
|
||||
34
u-boot/drivers/usb/musb-new/musb_debug.h
Normal file
34
u-boot/drivers/usb/musb-new/musb_debug.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* MUSB OTG driver debug defines
|
||||
*
|
||||
* Copyright 2005 Mentor Graphics Corporation
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
* Copyright (C) 2006-2007 Nokia Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_LINUX_DEBUG_H__
|
||||
#define __MUSB_LINUX_DEBUG_H__
|
||||
|
||||
#define yprintk(facility, format, args...) \
|
||||
do { printk(facility "%s %d: " format , \
|
||||
__func__, __LINE__ , ## args); } while (0)
|
||||
#define WARNING(fmt, args...) yprintk(KERN_WARNING, fmt, ## args)
|
||||
#define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args)
|
||||
#define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int musb_init_debugfs(struct musb *musb);
|
||||
void musb_exit_debugfs(struct musb *musb);
|
||||
#else
|
||||
static inline int musb_init_debugfs(struct musb *musb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void musb_exit_debugfs(struct musb *musb)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MUSB_LINUX_DEBUG_H__ */
|
||||
162
u-boot/drivers/usb/musb-new/musb_dma.h
Normal file
162
u-boot/drivers/usb/musb-new/musb_dma.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* MUSB OTG driver DMA controller abstraction
|
||||
*
|
||||
* Copyright 2005 Mentor Graphics Corporation
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
* Copyright (C) 2006-2007 Nokia Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_DMA_H__
|
||||
#define __MUSB_DMA_H__
|
||||
|
||||
struct musb_hw_ep;
|
||||
|
||||
/*
|
||||
* DMA Controller Abstraction
|
||||
*
|
||||
* DMA Controllers are abstracted to allow use of a variety of different
|
||||
* implementations of DMA, as allowed by the Inventra USB cores. On the
|
||||
* host side, usbcore sets up the DMA mappings and flushes caches; on the
|
||||
* peripheral side, the gadget controller driver does. Responsibilities
|
||||
* of a DMA controller driver include:
|
||||
*
|
||||
* - Handling the details of moving multiple USB packets
|
||||
* in cooperation with the Inventra USB core, including especially
|
||||
* the correct RX side treatment of short packets and buffer-full
|
||||
* states (both of which terminate transfers).
|
||||
*
|
||||
* - Knowing the correlation between dma channels and the
|
||||
* Inventra core's local endpoint resources and data direction.
|
||||
*
|
||||
* - Maintaining a list of allocated/available channels.
|
||||
*
|
||||
* - Updating channel status on interrupts,
|
||||
* whether shared with the Inventra core or separate.
|
||||
*/
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
#ifndef CONFIG_USB_MUSB_PIO_ONLY
|
||||
#define is_dma_capable() (1)
|
||||
#else
|
||||
#define is_dma_capable() (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_TI_CPPI_DMA
|
||||
#define is_cppi_enabled() 1
|
||||
#else
|
||||
#define is_cppi_enabled() 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_TUSB_OMAP_DMA
|
||||
#define tusb_dma_omap() 1
|
||||
#else
|
||||
#define tusb_dma_omap() 0
|
||||
#endif
|
||||
|
||||
/* Anomaly 05000456 - USB Receive Interrupt Is Not Generated in DMA Mode 1
|
||||
* Only allow DMA mode 1 to be used when the USB will actually generate the
|
||||
* interrupts we expect.
|
||||
*/
|
||||
#ifdef CONFIG_BLACKFIN
|
||||
# undef USE_MODE1
|
||||
# if !ANOMALY_05000456
|
||||
# define USE_MODE1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DMA channel status ... updated by the dma controller driver whenever that
|
||||
* status changes, and protected by the overall controller spinlock.
|
||||
*/
|
||||
enum dma_channel_status {
|
||||
/* unallocated */
|
||||
MUSB_DMA_STATUS_UNKNOWN,
|
||||
/* allocated ... but not busy, no errors */
|
||||
MUSB_DMA_STATUS_FREE,
|
||||
/* busy ... transactions are active */
|
||||
MUSB_DMA_STATUS_BUSY,
|
||||
/* transaction(s) aborted due to ... dma or memory bus error */
|
||||
MUSB_DMA_STATUS_BUS_ABORT,
|
||||
/* transaction(s) aborted due to ... core error or USB fault */
|
||||
MUSB_DMA_STATUS_CORE_ABORT
|
||||
};
|
||||
|
||||
struct dma_controller;
|
||||
|
||||
/**
|
||||
* struct dma_channel - A DMA channel.
|
||||
* @private_data: channel-private data
|
||||
* @max_len: the maximum number of bytes the channel can move in one
|
||||
* transaction (typically representing many USB maximum-sized packets)
|
||||
* @actual_len: how many bytes have been transferred
|
||||
* @status: current channel status (updated e.g. on interrupt)
|
||||
* @desired_mode: true if mode 1 is desired; false if mode 0 is desired
|
||||
*
|
||||
* channels are associated with an endpoint for the duration of at least
|
||||
* one usb transfer.
|
||||
*/
|
||||
struct dma_channel {
|
||||
void *private_data;
|
||||
/* FIXME not void* private_data, but a dma_controller * */
|
||||
size_t max_len;
|
||||
size_t actual_len;
|
||||
enum dma_channel_status status;
|
||||
bool desired_mode;
|
||||
};
|
||||
|
||||
/*
|
||||
* dma_channel_status - return status of dma channel
|
||||
* @c: the channel
|
||||
*
|
||||
* Returns the software's view of the channel status. If that status is BUSY
|
||||
* then it's possible that the hardware has completed (or aborted) a transfer,
|
||||
* so the driver needs to update that status.
|
||||
*/
|
||||
static inline enum dma_channel_status
|
||||
dma_channel_status(struct dma_channel *c)
|
||||
{
|
||||
return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dma_controller - A DMA Controller.
|
||||
* @start: call this to start a DMA controller;
|
||||
* return 0 on success, else negative errno
|
||||
* @stop: call this to stop a DMA controller
|
||||
* return 0 on success, else negative errno
|
||||
* @channel_alloc: call this to allocate a DMA channel
|
||||
* @channel_release: call this to release a DMA channel
|
||||
* @channel_abort: call this to abort a pending DMA transaction,
|
||||
* returning it to FREE (but allocated) state
|
||||
*
|
||||
* Controllers manage dma channels.
|
||||
*/
|
||||
struct dma_controller {
|
||||
int (*start)(struct dma_controller *);
|
||||
int (*stop)(struct dma_controller *);
|
||||
struct dma_channel *(*channel_alloc)(struct dma_controller *,
|
||||
struct musb_hw_ep *, u8 is_tx);
|
||||
void (*channel_release)(struct dma_channel *);
|
||||
int (*channel_program)(struct dma_channel *channel,
|
||||
u16 maxpacket, u8 mode,
|
||||
dma_addr_t dma_addr,
|
||||
u32 length);
|
||||
int (*channel_abort)(struct dma_channel *);
|
||||
int (*is_compatible)(struct dma_channel *channel,
|
||||
u16 maxpacket,
|
||||
void *buf, u32 length);
|
||||
};
|
||||
|
||||
/* called after channel_program(), may indicate a fault */
|
||||
extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
|
||||
|
||||
|
||||
extern struct dma_controller *__init
|
||||
dma_controller_create(struct musb *, void __iomem *);
|
||||
|
||||
extern void dma_controller_destroy(struct dma_controller *);
|
||||
|
||||
#endif /* __MUSB_DMA_H__ */
|
||||
762
u-boot/drivers/usb/musb-new/musb_dsps.c
Normal file
762
u-boot/drivers/usb/musb-new/musb_dsps.c
Normal file
@@ -0,0 +1,762 @@
|
||||
/*
|
||||
* Texas Instruments DSPS platforms "glue layer"
|
||||
*
|
||||
* Copyright (C) 2012, by Texas Instruments
|
||||
*
|
||||
* Based on the am35x "glue layer" code.
|
||||
*
|
||||
* This file is part of the Inventra Controller Driver for Linux.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* musb_dsps.c will be a common file for all the TI DSPS platforms
|
||||
* such as dm64x, dm36x, dm35x, da8x, am35x and ti81x.
|
||||
* For now only ti81x is using this and in future davinci.c, am35x.c
|
||||
* da8xx.c would be merged to this file after testing.
|
||||
*/
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <plat/usb.h>
|
||||
#else
|
||||
#include <common.h>
|
||||
#include <asm/omap_musb.h>
|
||||
#include "linux-compat.h"
|
||||
#endif
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
/**
|
||||
* avoid using musb_readx()/musb_writex() as glue layer should not be
|
||||
* dependent on musb core layer symbols.
|
||||
*/
|
||||
static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
|
||||
{ return __raw_readb(addr + offset); }
|
||||
|
||||
static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
|
||||
{ return __raw_readl(addr + offset); }
|
||||
|
||||
static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
|
||||
{ __raw_writeb(data, addr + offset); }
|
||||
|
||||
static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
|
||||
{ __raw_writel(data, addr + offset); }
|
||||
|
||||
/**
|
||||
* DSPS musb wrapper register offset.
|
||||
* FIXME: This should be expanded to have all the wrapper registers from TI DSPS
|
||||
* musb ips.
|
||||
*/
|
||||
struct dsps_musb_wrapper {
|
||||
u16 revision;
|
||||
u16 control;
|
||||
u16 status;
|
||||
u16 eoi;
|
||||
u16 epintr_set;
|
||||
u16 epintr_clear;
|
||||
u16 epintr_status;
|
||||
u16 coreintr_set;
|
||||
u16 coreintr_clear;
|
||||
u16 coreintr_status;
|
||||
u16 phy_utmi;
|
||||
u16 mode;
|
||||
|
||||
/* bit positions for control */
|
||||
unsigned reset:5;
|
||||
|
||||
/* bit positions for interrupt */
|
||||
unsigned usb_shift:5;
|
||||
u32 usb_mask;
|
||||
u32 usb_bitmap;
|
||||
unsigned drvvbus:5;
|
||||
|
||||
unsigned txep_shift:5;
|
||||
u32 txep_mask;
|
||||
u32 txep_bitmap;
|
||||
|
||||
unsigned rxep_shift:5;
|
||||
u32 rxep_mask;
|
||||
u32 rxep_bitmap;
|
||||
|
||||
/* bit positions for phy_utmi */
|
||||
unsigned otg_disable:5;
|
||||
|
||||
/* bit positions for mode */
|
||||
unsigned iddig:5;
|
||||
/* miscellaneous stuff */
|
||||
u32 musb_core_offset;
|
||||
u8 poll_seconds;
|
||||
};
|
||||
|
||||
static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = {
|
||||
.revision = 0x00,
|
||||
.control = 0x14,
|
||||
.status = 0x18,
|
||||
.eoi = 0x24,
|
||||
.epintr_set = 0x38,
|
||||
.epintr_clear = 0x40,
|
||||
.epintr_status = 0x30,
|
||||
.coreintr_set = 0x3c,
|
||||
.coreintr_clear = 0x44,
|
||||
.coreintr_status = 0x34,
|
||||
.phy_utmi = 0xe0,
|
||||
.mode = 0xe8,
|
||||
.reset = 0,
|
||||
.otg_disable = 21,
|
||||
.iddig = 8,
|
||||
.usb_shift = 0,
|
||||
.usb_mask = 0x1ff,
|
||||
.usb_bitmap = (0x1ff << 0),
|
||||
.drvvbus = 8,
|
||||
.txep_shift = 0,
|
||||
.txep_mask = 0xffff,
|
||||
.txep_bitmap = (0xffff << 0),
|
||||
.rxep_shift = 16,
|
||||
.rxep_mask = 0xfffe,
|
||||
.rxep_bitmap = (0xfffe << 16),
|
||||
.musb_core_offset = 0x400,
|
||||
.poll_seconds = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* DSPS glue structure.
|
||||
*/
|
||||
struct dsps_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb; /* child musb pdev */
|
||||
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
|
||||
struct timer_list timer; /* otg_workaround timer */
|
||||
};
|
||||
|
||||
/**
|
||||
* dsps_musb_enable - enable interrupts
|
||||
*/
|
||||
#ifndef __UBOOT__
|
||||
static void dsps_musb_enable(struct musb *musb)
|
||||
#else
|
||||
static int dsps_musb_enable(struct musb *musb)
|
||||
#endif
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct platform_device *pdev = to_platform_device(dev->parent);
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
#else
|
||||
const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
|
||||
#endif
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 epmask, coremask;
|
||||
|
||||
/* Workaround: setup IRQs through both register sets. */
|
||||
epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) |
|
||||
((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
|
||||
coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
|
||||
|
||||
dsps_writel(reg_base, wrp->epintr_set, epmask);
|
||||
dsps_writel(reg_base, wrp->coreintr_set, coremask);
|
||||
/* Force the DRVVBUS IRQ so we can start polling for ID change. */
|
||||
#ifndef __UBOOT__
|
||||
if (is_otg_enabled(musb))
|
||||
dsps_writel(reg_base, wrp->coreintr_set,
|
||||
(1 << wrp->drvvbus) << wrp->usb_shift);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* dsps_musb_disable - disable HDRC and flush interrupts
|
||||
*/
|
||||
static void dsps_musb_disable(struct musb *musb)
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct platform_device *pdev = to_platform_device(dev->parent);
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
|
||||
dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
|
||||
dsps_writel(reg_base, wrp->epintr_clear,
|
||||
wrp->txep_bitmap | wrp->rxep_bitmap);
|
||||
dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
||||
dsps_writel(reg_base, wrp->eoi, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static void otg_timer(unsigned long _musb)
|
||||
{
|
||||
struct musb *musb = (void *)_musb;
|
||||
void __iomem *mregs = musb->mregs;
|
||||
struct device *dev = musb->controller;
|
||||
struct platform_device *pdev = to_platform_device(dev->parent);
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
u8 devctl;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* We poll because DSPS IP's won't expose several OTG-critical
|
||||
* status change events (from the transceiver) otherwise.
|
||||
*/
|
||||
devctl = dsps_readb(mregs, MUSB_DEVCTL);
|
||||
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
|
||||
otg_state_string(musb->xceiv->state));
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
switch (musb->xceiv->state) {
|
||||
case OTG_STATE_A_WAIT_BCON:
|
||||
devctl &= ~MUSB_DEVCTL_SESSION;
|
||||
dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
|
||||
devctl = dsps_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:
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
dsps_writel(musb->ctrl_base, wrp->coreintr_set,
|
||||
MUSB_INTR_VBUSERROR << wrp->usb_shift);
|
||||
break;
|
||||
case OTG_STATE_B_IDLE:
|
||||
if (!is_peripheral_enabled(musb))
|
||||
break;
|
||||
|
||||
devctl = dsps_readb(mregs, MUSB_DEVCTL);
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE)
|
||||
mod_timer(&glue->timer,
|
||||
jiffies + wrp->poll_seconds * HZ);
|
||||
else
|
||||
musb->xceiv->state = OTG_STATE_A_IDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct platform_device *pdev = to_platform_device(dev->parent);
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
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)) {
|
||||
dev_dbg(musb->controller, "%s active, deleting timer\n",
|
||||
otg_state_string(musb->xceiv->state));
|
||||
del_timer(&glue->timer);
|
||||
last_timer = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) {
|
||||
dev_dbg(musb->controller,
|
||||
"Longer idle timer already pending, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
last_timer = timeout;
|
||||
|
||||
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
jiffies_to_msecs(timeout - jiffies));
|
||||
mod_timer(&glue->timer, timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
static irqreturn_t dsps_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct platform_device *pdev = to_platform_device(dev->parent);
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
#else
|
||||
const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
|
||||
#endif
|
||||
unsigned long flags;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 epintr, usbintr;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
/* Get endpoint interrupts */
|
||||
epintr = dsps_readl(reg_base, wrp->epintr_status);
|
||||
musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
|
||||
musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
|
||||
|
||||
if (epintr)
|
||||
dsps_writel(reg_base, wrp->epintr_status, epintr);
|
||||
|
||||
/* Get usb core interrupts */
|
||||
usbintr = dsps_readl(reg_base, wrp->coreintr_status);
|
||||
if (!usbintr && !epintr)
|
||||
goto eoi;
|
||||
|
||||
musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
|
||||
if (usbintr)
|
||||
dsps_writel(reg_base, wrp->coreintr_status, usbintr);
|
||||
|
||||
dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
|
||||
usbintr, epintr);
|
||||
#ifndef __UBOOT__
|
||||
/*
|
||||
* DRVVBUS IRQs are the only proxy we have (a very poor one!) for
|
||||
* DSPS IP'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 & MUSB_INTR_BABBLE) && is_host_enabled(musb))
|
||||
pr_info("CAUTION: musb: Babble Interrupt Occured\n");
|
||||
|
||||
if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
|
||||
int drvvbus = dsps_readl(reg_base, wrp->status);
|
||||
void __iomem *mregs = musb->mregs;
|
||||
u8 devctl = dsps_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(&glue->timer,
|
||||
jiffies + wrp->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->otg->default_a = 1;
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
del_timer(&glue->timer);
|
||||
} else {
|
||||
musb->is_active = 0;
|
||||
MUSB_DEV_MODE(musb);
|
||||
musb->xceiv->otg->default_a = 0;
|
||||
musb->xceiv->state = OTG_STATE_B_IDLE;
|
||||
}
|
||||
|
||||
/* NOTE: this must complete power-on within 100 ms. */
|
||||
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
drvvbus ? "on" : "off",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
err ? " ERROR" : "",
|
||||
devctl);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (musb->int_tx || musb->int_rx || musb->int_usb)
|
||||
ret |= musb_interrupt(musb);
|
||||
|
||||
eoi:
|
||||
/* EOI needs to be written for the IRQ to be re-asserted. */
|
||||
if (ret == IRQ_HANDLED || epintr || usbintr)
|
||||
dsps_writel(reg_base, wrp->eoi, 1);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* Poll for ID change */
|
||||
if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
|
||||
mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
|
||||
#endif
|
||||
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dsps_musb_init(struct musb *musb)
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct platform_device *pdev = to_platform_device(dev->parent);
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
#else
|
||||
struct omap_musb_board_data *data =
|
||||
(struct omap_musb_board_data *)musb->controller;
|
||||
const struct dsps_musb_wrapper *wrp = &ti81xx_driver_data;
|
||||
#endif
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 rev, val;
|
||||
int status;
|
||||
|
||||
/* mentor core register starts at offset of 0x400 from musb base */
|
||||
musb->mregs += wrp->musb_core_offset;
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* NOP driver needs change if supporting dual instance */
|
||||
usb_nop_xceiv_register();
|
||||
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(musb->xceiv))
|
||||
return -ENODEV;
|
||||
#endif
|
||||
|
||||
/* Returns zero if e.g. not clocked */
|
||||
rev = dsps_readl(reg_base, wrp->revision);
|
||||
if (!rev) {
|
||||
status = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
if (is_host_enabled(musb))
|
||||
setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
|
||||
#endif
|
||||
|
||||
/* Reset the musb */
|
||||
dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(1);
|
||||
|
||||
musb->isr = dsps_interrupt;
|
||||
|
||||
/* reset the otgdisable bit, needed for host mode to work */
|
||||
val = dsps_readl(reg_base, wrp->phy_utmi);
|
||||
val &= ~(1 << wrp->otg_disable);
|
||||
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
|
||||
|
||||
/* clear level interrupt */
|
||||
dsps_writel(reg_base, wrp->eoi, 0);
|
||||
|
||||
return 0;
|
||||
err0:
|
||||
#ifndef __UBOOT__
|
||||
usb_put_phy(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
static int dsps_musb_exit(struct musb *musb)
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
struct platform_device *pdev = to_platform_device(dev->parent);
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
#else
|
||||
struct omap_musb_board_data *data =
|
||||
(struct omap_musb_board_data *)musb->controller;
|
||||
#endif
|
||||
|
||||
#ifndef __UBOOT__
|
||||
if (is_host_enabled(musb))
|
||||
del_timer_sync(&glue->timer);
|
||||
#endif
|
||||
|
||||
/* Shutdown the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(0);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* NOP driver needs change if supporting dual instance */
|
||||
usb_put_phy(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static struct musb_platform_ops dsps_ops = {
|
||||
#else
|
||||
struct musb_platform_ops musb_dsps_ops = {
|
||||
#endif
|
||||
.init = dsps_musb_init,
|
||||
.exit = dsps_musb_exit,
|
||||
|
||||
.enable = dsps_musb_enable,
|
||||
.disable = dsps_musb_disable,
|
||||
|
||||
#ifndef __UBOOT__
|
||||
.try_idle = dsps_musb_try_idle,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static u64 musb_dmamask = DMA_BIT_MASK(32);
|
||||
#endif
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
|
||||
{
|
||||
struct device *dev = glue->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct musb_hdrc_platform_data *pdata = dev->platform_data;
|
||||
struct platform_device *musb;
|
||||
struct resource *res;
|
||||
struct resource resources[2];
|
||||
char res_name[10];
|
||||
int ret;
|
||||
|
||||
/* get memory resource */
|
||||
sprintf(res_name, "musb%d", id);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
|
||||
if (!res) {
|
||||
dev_err(dev, "%s get mem resource failed\n", res_name);
|
||||
ret = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
res->parent = NULL;
|
||||
resources[0] = *res;
|
||||
|
||||
/* get irq resource */
|
||||
sprintf(res_name, "musb%d-irq", id);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
|
||||
if (!res) {
|
||||
dev_err(dev, "%s get irq resource failed\n", res_name);
|
||||
ret = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
res->parent = NULL;
|
||||
resources[1] = *res;
|
||||
resources[1].name = "mc";
|
||||
|
||||
/* allocate the child platform device */
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(dev, "failed to allocate musb device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb->dev.parent = dev;
|
||||
musb->dev.dma_mask = &musb_dmamask;
|
||||
musb->dev.coherent_dma_mask = musb_dmamask;
|
||||
|
||||
glue->musb = musb;
|
||||
|
||||
pdata->platform_ops = &dsps_ops;
|
||||
|
||||
ret = platform_device_add_resources(musb, resources, 2);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add resources\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add platform_data\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
platform_device_put(musb);
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue)
|
||||
{
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
}
|
||||
|
||||
static int __devinit dsps_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
const struct dsps_musb_wrapper *wrp =
|
||||
(struct dsps_musb_wrapper *)id->driver_data;
|
||||
struct dsps_glue *glue;
|
||||
struct resource *iomem;
|
||||
int ret;
|
||||
|
||||
/* allocate glue */
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "unable to allocate glue memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* get memory resource */
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iomem) {
|
||||
dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
|
||||
ret = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
|
||||
glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
|
||||
if (!glue->wrp) {
|
||||
dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
/* enable the usbss clocks */
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* create the child platform device for first instances of musb */
|
||||
ret = dsps_create_musb_pdev(glue, 0);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "failed to create child pdev\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
pm_runtime_put(&pdev->dev);
|
||||
err2:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
kfree(glue->wrp);
|
||||
err1:
|
||||
kfree(glue);
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
static int __devexit dsps_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dsps_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
/* delete the child platform device */
|
||||
dsps_delete_musb_pdev(glue);
|
||||
|
||||
/* disable usbss clocks */
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
kfree(glue->wrp);
|
||||
kfree(glue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dsps_suspend(struct device *dev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
|
||||
/* Shutdown the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsps_resume(struct device *dev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
|
||||
#endif
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
|
||||
{
|
||||
.name = "musb-ti81xx",
|
||||
.driver_data = (kernel_ulong_t) &ti81xx_driver_data,
|
||||
},
|
||||
{ }, /* Terminating Entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
|
||||
|
||||
static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
|
||||
{ .compatible = "musb-ti81xx", },
|
||||
{ .compatible = "ti,ti81xx-musb", },
|
||||
{ .compatible = "ti,am335x-musb", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
|
||||
|
||||
static struct platform_driver dsps_usbss_driver = {
|
||||
.probe = dsps_probe,
|
||||
.remove = __devexit_p(dsps_remove),
|
||||
.driver = {
|
||||
.name = "musb-dsps",
|
||||
.pm = &dsps_pm_ops,
|
||||
.of_match_table = musb_dsps_of_match,
|
||||
},
|
||||
.id_table = musb_dsps_id_table,
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
|
||||
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init dsps_init(void)
|
||||
{
|
||||
return platform_driver_register(&dsps_usbss_driver);
|
||||
}
|
||||
subsys_initcall(dsps_init);
|
||||
|
||||
static void __exit dsps_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&dsps_usbss_driver);
|
||||
}
|
||||
module_exit(dsps_exit);
|
||||
#endif
|
||||
2308
u-boot/drivers/usb/musb-new/musb_gadget.c
Normal file
2308
u-boot/drivers/usb/musb-new/musb_gadget.c
Normal file
File diff suppressed because it is too large
Load Diff
106
u-boot/drivers/usb/musb-new/musb_gadget.h
Normal file
106
u-boot/drivers/usb/musb-new/musb_gadget.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* MUSB OTG driver peripheral defines
|
||||
*
|
||||
* Copyright 2005 Mentor Graphics Corporation
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
* Copyright (C) 2006-2007 Nokia Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_GADGET_H
|
||||
#define __MUSB_GADGET_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#ifdef __UBOOT__
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/errno.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#endif
|
||||
|
||||
enum buffer_map_state {
|
||||
UN_MAPPED = 0,
|
||||
PRE_MAPPED,
|
||||
MUSB_MAPPED
|
||||
};
|
||||
|
||||
struct musb_request {
|
||||
struct usb_request request;
|
||||
struct list_head list;
|
||||
struct musb_ep *ep;
|
||||
struct musb *musb;
|
||||
u8 tx; /* endpoint direction */
|
||||
u8 epnum;
|
||||
enum buffer_map_state map_state;
|
||||
};
|
||||
|
||||
static inline struct musb_request *to_musb_request(struct usb_request *req)
|
||||
{
|
||||
return req ? container_of(req, struct musb_request, request) : NULL;
|
||||
}
|
||||
|
||||
extern struct usb_request *
|
||||
musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
|
||||
extern void musb_free_request(struct usb_ep *ep, struct usb_request *req);
|
||||
|
||||
|
||||
/*
|
||||
* struct musb_ep - peripheral side view of endpoint rx or tx side
|
||||
*/
|
||||
struct musb_ep {
|
||||
/* stuff towards the head is basically write-once. */
|
||||
struct usb_ep end_point;
|
||||
char name[12];
|
||||
struct musb_hw_ep *hw_ep;
|
||||
struct musb *musb;
|
||||
u8 current_epnum;
|
||||
|
||||
/* ... when enabled/disabled ... */
|
||||
u8 type;
|
||||
u8 is_in;
|
||||
u16 packet_sz;
|
||||
const struct usb_endpoint_descriptor *desc;
|
||||
struct dma_channel *dma;
|
||||
|
||||
/* later things are modified based on usage */
|
||||
struct list_head req_list;
|
||||
|
||||
u8 wedged;
|
||||
|
||||
/* true if lock must be dropped but req_list may not be advanced */
|
||||
u8 busy;
|
||||
|
||||
u8 hb_mult;
|
||||
};
|
||||
|
||||
static inline struct musb_ep *to_musb_ep(struct usb_ep *ep)
|
||||
{
|
||||
return ep ? container_of(ep, struct musb_ep, end_point) : NULL;
|
||||
}
|
||||
|
||||
static inline struct musb_request *next_request(struct musb_ep *ep)
|
||||
{
|
||||
struct list_head *queue = &ep->req_list;
|
||||
|
||||
if (list_empty(queue))
|
||||
return NULL;
|
||||
return container_of(queue->next, struct musb_request, list);
|
||||
}
|
||||
|
||||
extern void musb_g_tx(struct musb *musb, u8 epnum);
|
||||
extern void musb_g_rx(struct musb *musb, u8 epnum);
|
||||
|
||||
extern const struct usb_ep_ops musb_g_ep0_ops;
|
||||
|
||||
extern int musb_gadget_setup(struct musb *);
|
||||
extern void musb_gadget_cleanup(struct musb *);
|
||||
|
||||
extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
|
||||
|
||||
extern void musb_ep_restart(struct musb *, struct musb_request *);
|
||||
|
||||
#ifdef __UBOOT__
|
||||
int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver);
|
||||
#endif
|
||||
#endif /* __MUSB_GADGET_H */
|
||||
1065
u-boot/drivers/usb/musb-new/musb_gadget_ep0.c
Normal file
1065
u-boot/drivers/usb/musb-new/musb_gadget_ep0.c
Normal file
File diff suppressed because it is too large
Load Diff
2389
u-boot/drivers/usb/musb-new/musb_host.c
Normal file
2389
u-boot/drivers/usb/musb-new/musb_host.c
Normal file
File diff suppressed because it is too large
Load Diff
91
u-boot/drivers/usb/musb-new/musb_host.h
Normal file
91
u-boot/drivers/usb/musb-new/musb_host.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* MUSB OTG driver host defines
|
||||
*
|
||||
* Copyright 2005 Mentor Graphics Corporation
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
* Copyright (C) 2006-2007 Nokia Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MUSB_HOST_H
|
||||
#define _MUSB_HOST_H
|
||||
#ifdef __UBOOT__
|
||||
#include "usb-compat.h"
|
||||
#endif
|
||||
|
||||
static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
|
||||
{
|
||||
return container_of((void *) musb, struct usb_hcd, hcd_priv);
|
||||
}
|
||||
|
||||
static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
|
||||
{
|
||||
return (struct musb *) (hcd->hcd_priv);
|
||||
}
|
||||
|
||||
/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */
|
||||
struct musb_qh {
|
||||
struct usb_host_endpoint *hep; /* usbcore info */
|
||||
struct usb_device *dev;
|
||||
struct musb_hw_ep *hw_ep; /* current binding */
|
||||
|
||||
struct list_head ring; /* of musb_qh */
|
||||
/* struct musb_qh *next; */ /* for periodic tree */
|
||||
u8 mux; /* qh multiplexed to hw_ep */
|
||||
|
||||
unsigned offset; /* in urb->transfer_buffer */
|
||||
unsigned segsize; /* current xfer fragment */
|
||||
|
||||
u8 type_reg; /* {rx,tx} type register */
|
||||
u8 intv_reg; /* {rx,tx} interval register */
|
||||
u8 addr_reg; /* device address register */
|
||||
u8 h_addr_reg; /* hub address register */
|
||||
u8 h_port_reg; /* hub port register */
|
||||
|
||||
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[] */
|
||||
};
|
||||
|
||||
/* map from control or bulk queue head to the first qh on that ring */
|
||||
static inline struct musb_qh *first_qh(struct list_head *q)
|
||||
{
|
||||
if (list_empty(q))
|
||||
return NULL;
|
||||
return list_entry(q->next, struct musb_qh, ring);
|
||||
}
|
||||
|
||||
|
||||
extern void musb_root_disconnect(struct musb *musb);
|
||||
|
||||
struct usb_hcd;
|
||||
|
||||
extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf);
|
||||
extern int musb_hub_control(struct usb_hcd *hcd,
|
||||
u16 typeReq, u16 wValue, u16 wIndex,
|
||||
char *buf, u16 wLength);
|
||||
|
||||
extern const struct hc_driver musb_hc_driver;
|
||||
|
||||
static inline struct urb *next_urb(struct musb_qh *qh)
|
||||
{
|
||||
struct list_head *queue;
|
||||
|
||||
if (!qh)
|
||||
return NULL;
|
||||
queue = &qh->hep->urb_list;
|
||||
if (list_empty(queue))
|
||||
return NULL;
|
||||
return list_entry(queue->next, struct urb, urb_list);
|
||||
}
|
||||
|
||||
#ifdef __UBOOT__
|
||||
int musb_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
|
||||
int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
|
||||
#endif
|
||||
#endif /* _MUSB_HOST_H */
|
||||
126
u-boot/drivers/usb/musb-new/musb_io.h
Normal file
126
u-boot/drivers/usb/musb-new/musb_io.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* MUSB OTG driver register I/O
|
||||
*
|
||||
* Copyright 2005 Mentor Graphics Corporation
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
* Copyright (C) 2006-2007 Nokia Corporation
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__
|
||||
#define __MUSB_LINUX_PLATFORM_ARCH_H__
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/io.h>
|
||||
#else
|
||||
#include <asm/io.h>
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
|
||||
&& !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \
|
||||
&& !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) \
|
||||
&& !defined(CONFIG_MIPS) && !defined(CONFIG_M68K)
|
||||
static inline void readsl(const void __iomem *addr, void *buf, int len)
|
||||
{ insl((unsigned long)addr, buf, len); }
|
||||
static inline void readsw(const void __iomem *addr, void *buf, int len)
|
||||
{ insw((unsigned long)addr, buf, len); }
|
||||
static inline void readsb(const void __iomem *addr, void *buf, int len)
|
||||
{ insb((unsigned long)addr, buf, len); }
|
||||
|
||||
static inline void writesl(const void __iomem *addr, const void *buf, int len)
|
||||
{ outsl((unsigned long)addr, buf, len); }
|
||||
static inline void writesw(const void __iomem *addr, const void *buf, int len)
|
||||
{ outsw((unsigned long)addr, buf, len); }
|
||||
static inline void writesb(const void __iomem *addr, const void *buf, int len)
|
||||
{ outsb((unsigned long)addr, buf, len); }
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BLACKFIN
|
||||
|
||||
/* NOTE: these offsets are all in bytes */
|
||||
|
||||
static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
|
||||
{ return __raw_readw(addr + offset); }
|
||||
|
||||
static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
|
||||
{ return __raw_readl(addr + offset); }
|
||||
|
||||
|
||||
static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
|
||||
{ __raw_writew(data, addr + offset); }
|
||||
|
||||
static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
|
||||
{ __raw_writel(data, addr + offset); }
|
||||
|
||||
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
|
||||
|
||||
/*
|
||||
* TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
|
||||
*/
|
||||
static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
|
||||
{
|
||||
u16 tmp;
|
||||
u8 val;
|
||||
|
||||
tmp = __raw_readw(addr + (offset & ~1));
|
||||
if (offset & 1)
|
||||
val = (tmp >> 8);
|
||||
else
|
||||
val = tmp & 0xff;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
|
||||
{
|
||||
u16 tmp;
|
||||
|
||||
tmp = __raw_readw(addr + (offset & ~1));
|
||||
if (offset & 1)
|
||||
tmp = (data << 8) | (tmp & 0xff);
|
||||
else
|
||||
tmp = (tmp & 0xff00) | data;
|
||||
|
||||
__raw_writew(tmp, addr + (offset & ~1));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
|
||||
{ return __raw_readb(addr + offset); }
|
||||
|
||||
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
|
||||
{ __raw_writeb(data, addr + offset); }
|
||||
|
||||
#endif /* CONFIG_USB_MUSB_TUSB6010 */
|
||||
|
||||
#else
|
||||
|
||||
static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
|
||||
{ return (u8) (bfin_read16(addr + offset)); }
|
||||
|
||||
static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
|
||||
{ return bfin_read16(addr + offset); }
|
||||
|
||||
static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
|
||||
{ return (u32) (bfin_read16(addr + offset)); }
|
||||
|
||||
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
|
||||
{ bfin_write16(addr + offset, (u16) data); }
|
||||
|
||||
static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
|
||||
{ bfin_write16(addr + offset, data); }
|
||||
|
||||
static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
|
||||
{ bfin_write16(addr + offset, (u16) data); }
|
||||
|
||||
#endif /* CONFIG_BLACKFIN */
|
||||
|
||||
#endif
|
||||
718
u-boot/drivers/usb/musb-new/musb_regs.h
Normal file
718
u-boot/drivers/usb/musb-new/musb_regs.h
Normal file
@@ -0,0 +1,718 @@
|
||||
/*
|
||||
* MUSB OTG driver register defines
|
||||
*
|
||||
* Copyright 2005 Mentor Graphics Corporation
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
* Copyright (C) 2006-2007 Nokia Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_REGS_H__
|
||||
#define __MUSB_REGS_H__
|
||||
|
||||
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
|
||||
|
||||
/*
|
||||
* MUSB Register bits
|
||||
*/
|
||||
|
||||
/* POWER */
|
||||
#define MUSB_POWER_ISOUPDATE 0x80
|
||||
#define MUSB_POWER_SOFTCONN 0x40
|
||||
#define MUSB_POWER_HSENAB 0x20
|
||||
#define MUSB_POWER_HSMODE 0x10
|
||||
#define MUSB_POWER_RESET 0x08
|
||||
#define MUSB_POWER_RESUME 0x04
|
||||
#define MUSB_POWER_SUSPENDM 0x02
|
||||
#define MUSB_POWER_ENSUSPEND 0x01
|
||||
|
||||
/* INTRUSB */
|
||||
#define MUSB_INTR_SUSPEND 0x01
|
||||
#define MUSB_INTR_RESUME 0x02
|
||||
#define MUSB_INTR_RESET 0x04
|
||||
#define MUSB_INTR_BABBLE 0x04
|
||||
#define MUSB_INTR_SOF 0x08
|
||||
#define MUSB_INTR_CONNECT 0x10
|
||||
#define MUSB_INTR_DISCONNECT 0x20
|
||||
#define MUSB_INTR_SESSREQ 0x40
|
||||
#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */
|
||||
|
||||
/* DEVCTL */
|
||||
#define MUSB_DEVCTL_BDEVICE 0x80
|
||||
#define MUSB_DEVCTL_FSDEV 0x40
|
||||
#define MUSB_DEVCTL_LSDEV 0x20
|
||||
#define MUSB_DEVCTL_VBUS 0x18
|
||||
#define MUSB_DEVCTL_VBUS_SHIFT 3
|
||||
#define MUSB_DEVCTL_HM 0x04
|
||||
#define MUSB_DEVCTL_HR 0x02
|
||||
#define MUSB_DEVCTL_SESSION 0x01
|
||||
|
||||
/* MUSB ULPI VBUSCONTROL */
|
||||
#define MUSB_ULPI_USE_EXTVBUS 0x01
|
||||
#define MUSB_ULPI_USE_EXTVBUSIND 0x02
|
||||
/* ULPI_REG_CONTROL */
|
||||
#define MUSB_ULPI_REG_REQ (1 << 0)
|
||||
#define MUSB_ULPI_REG_CMPLT (1 << 1)
|
||||
#define MUSB_ULPI_RDN_WR (1 << 2)
|
||||
|
||||
/* TESTMODE */
|
||||
#define MUSB_TEST_FORCE_HOST 0x80
|
||||
#define MUSB_TEST_FIFO_ACCESS 0x40
|
||||
#define MUSB_TEST_FORCE_FS 0x20
|
||||
#define MUSB_TEST_FORCE_HS 0x10
|
||||
#define MUSB_TEST_PACKET 0x08
|
||||
#define MUSB_TEST_K 0x04
|
||||
#define MUSB_TEST_J 0x02
|
||||
#define MUSB_TEST_SE0_NAK 0x01
|
||||
|
||||
/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
|
||||
#define MUSB_FIFOSZ_DPB 0x10
|
||||
/* Allocation size (8, 16, 32, ... 4096) */
|
||||
#define MUSB_FIFOSZ_SIZE 0x0f
|
||||
|
||||
/* CSR0 */
|
||||
#define MUSB_CSR0_FLUSHFIFO 0x0100
|
||||
#define MUSB_CSR0_TXPKTRDY 0x0002
|
||||
#define MUSB_CSR0_RXPKTRDY 0x0001
|
||||
|
||||
/* CSR0 in Peripheral mode */
|
||||
#define MUSB_CSR0_P_SVDSETUPEND 0x0080
|
||||
#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040
|
||||
#define MUSB_CSR0_P_SENDSTALL 0x0020
|
||||
#define MUSB_CSR0_P_SETUPEND 0x0010
|
||||
#define MUSB_CSR0_P_DATAEND 0x0008
|
||||
#define MUSB_CSR0_P_SENTSTALL 0x0004
|
||||
|
||||
/* CSR0 in Host mode */
|
||||
#define MUSB_CSR0_H_DIS_PING 0x0800
|
||||
#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */
|
||||
#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */
|
||||
#define MUSB_CSR0_H_NAKTIMEOUT 0x0080
|
||||
#define MUSB_CSR0_H_STATUSPKT 0x0040
|
||||
#define MUSB_CSR0_H_REQPKT 0x0020
|
||||
#define MUSB_CSR0_H_ERROR 0x0010
|
||||
#define MUSB_CSR0_H_SETUPPKT 0x0008
|
||||
#define MUSB_CSR0_H_RXSTALL 0x0004
|
||||
|
||||
/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
|
||||
#define MUSB_CSR0_P_WZC_BITS \
|
||||
(MUSB_CSR0_P_SENTSTALL)
|
||||
#define MUSB_CSR0_H_WZC_BITS \
|
||||
(MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
|
||||
| MUSB_CSR0_RXPKTRDY)
|
||||
|
||||
/* TxType/RxType */
|
||||
#define MUSB_TYPE_SPEED 0xc0
|
||||
#define MUSB_TYPE_SPEED_SHIFT 6
|
||||
#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */
|
||||
#define MUSB_TYPE_PROTO_SHIFT 4
|
||||
#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */
|
||||
|
||||
/* CONFIGDATA */
|
||||
#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */
|
||||
#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */
|
||||
#define MUSB_CONFIGDATA_BIGENDIAN 0x20
|
||||
#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
|
||||
#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
|
||||
#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */
|
||||
#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
|
||||
#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */
|
||||
|
||||
/* TXCSR in Peripheral and Host mode */
|
||||
#define MUSB_TXCSR_AUTOSET 0x8000
|
||||
#define MUSB_TXCSR_DMAENAB 0x1000
|
||||
#define MUSB_TXCSR_FRCDATATOG 0x0800
|
||||
#define MUSB_TXCSR_DMAMODE 0x0400
|
||||
#define MUSB_TXCSR_CLRDATATOG 0x0040
|
||||
#define MUSB_TXCSR_FLUSHFIFO 0x0008
|
||||
#define MUSB_TXCSR_FIFONOTEMPTY 0x0002
|
||||
#define MUSB_TXCSR_TXPKTRDY 0x0001
|
||||
|
||||
/* TXCSR in Peripheral mode */
|
||||
#define MUSB_TXCSR_P_ISO 0x4000
|
||||
#define MUSB_TXCSR_P_INCOMPTX 0x0080
|
||||
#define MUSB_TXCSR_P_SENTSTALL 0x0020
|
||||
#define MUSB_TXCSR_P_SENDSTALL 0x0010
|
||||
#define MUSB_TXCSR_P_UNDERRUN 0x0004
|
||||
|
||||
/* TXCSR in Host mode */
|
||||
#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200
|
||||
#define MUSB_TXCSR_H_DATATOGGLE 0x0100
|
||||
#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080
|
||||
#define MUSB_TXCSR_H_RXSTALL 0x0020
|
||||
#define MUSB_TXCSR_H_ERROR 0x0004
|
||||
|
||||
/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
|
||||
#define MUSB_TXCSR_P_WZC_BITS \
|
||||
(MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
|
||||
| MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
|
||||
#define MUSB_TXCSR_H_WZC_BITS \
|
||||
(MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
|
||||
| MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
|
||||
|
||||
/* RXCSR in Peripheral and Host mode */
|
||||
#define MUSB_RXCSR_AUTOCLEAR 0x8000
|
||||
#define MUSB_RXCSR_DMAENAB 0x2000
|
||||
#define MUSB_RXCSR_DISNYET 0x1000
|
||||
#define MUSB_RXCSR_PID_ERR 0x1000
|
||||
#define MUSB_RXCSR_DMAMODE 0x0800
|
||||
#define MUSB_RXCSR_INCOMPRX 0x0100
|
||||
#define MUSB_RXCSR_CLRDATATOG 0x0080
|
||||
#define MUSB_RXCSR_FLUSHFIFO 0x0010
|
||||
#define MUSB_RXCSR_DATAERROR 0x0008
|
||||
#define MUSB_RXCSR_FIFOFULL 0x0002
|
||||
#define MUSB_RXCSR_RXPKTRDY 0x0001
|
||||
|
||||
/* RXCSR in Peripheral mode */
|
||||
#define MUSB_RXCSR_P_ISO 0x4000
|
||||
#define MUSB_RXCSR_P_SENTSTALL 0x0040
|
||||
#define MUSB_RXCSR_P_SENDSTALL 0x0020
|
||||
#define MUSB_RXCSR_P_OVERRUN 0x0004
|
||||
|
||||
/* RXCSR in Host mode */
|
||||
#define MUSB_RXCSR_H_AUTOREQ 0x4000
|
||||
#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400
|
||||
#define MUSB_RXCSR_H_DATATOGGLE 0x0200
|
||||
#define MUSB_RXCSR_H_RXSTALL 0x0040
|
||||
#define MUSB_RXCSR_H_REQPKT 0x0020
|
||||
#define MUSB_RXCSR_H_ERROR 0x0004
|
||||
|
||||
/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
|
||||
#define MUSB_RXCSR_P_WZC_BITS \
|
||||
(MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
|
||||
| MUSB_RXCSR_RXPKTRDY)
|
||||
#define MUSB_RXCSR_H_WZC_BITS \
|
||||
(MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
|
||||
| MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
|
||||
|
||||
/* HUBADDR */
|
||||
#define MUSB_HUBADDR_MULTI_TT 0x80
|
||||
|
||||
|
||||
#ifndef CONFIG_BLACKFIN
|
||||
|
||||
/* SUNXI has different reg addresses, but identical r/w functions */
|
||||
#ifndef CONFIG_ARCH_SUNXI
|
||||
|
||||
/*
|
||||
* Common USB registers
|
||||
*/
|
||||
|
||||
#define MUSB_FADDR 0x00 /* 8-bit */
|
||||
#define MUSB_POWER 0x01 /* 8-bit */
|
||||
|
||||
#define MUSB_INTRTX 0x02 /* 16-bit */
|
||||
#define MUSB_INTRRX 0x04
|
||||
#define MUSB_INTRTXE 0x06
|
||||
#define MUSB_INTRRXE 0x08
|
||||
#define MUSB_INTRUSB 0x0A /* 8 bit */
|
||||
#define MUSB_INTRUSBE 0x0B /* 8 bit */
|
||||
#define MUSB_FRAME 0x0C
|
||||
#define MUSB_INDEX 0x0E /* 8 bit */
|
||||
#define MUSB_TESTMODE 0x0F /* 8 bit */
|
||||
|
||||
/* Get offset for a given FIFO from musb->mregs */
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
|
||||
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
|
||||
#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
|
||||
#else
|
||||
#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Additional Control Registers
|
||||
*/
|
||||
|
||||
#define MUSB_DEVCTL 0x60 /* 8 bit */
|
||||
|
||||
/* These are always controlled through the INDEX register */
|
||||
#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */
|
||||
#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */
|
||||
#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */
|
||||
#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */
|
||||
|
||||
/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
|
||||
#define MUSB_HWVERS 0x6C /* 8 bit */
|
||||
#define MUSB_ULPI_BUSCONTROL 0x70 /* 8 bit */
|
||||
#define MUSB_ULPI_INT_MASK 0x72 /* 8 bit */
|
||||
#define MUSB_ULPI_INT_SRC 0x73 /* 8 bit */
|
||||
#define MUSB_ULPI_REG_DATA 0x74 /* 8 bit */
|
||||
#define MUSB_ULPI_REG_ADDR 0x75 /* 8 bit */
|
||||
#define MUSB_ULPI_REG_CONTROL 0x76 /* 8 bit */
|
||||
#define MUSB_ULPI_RAW_DATA 0x77 /* 8 bit */
|
||||
|
||||
#define MUSB_EPINFO 0x78 /* 8 bit */
|
||||
#define MUSB_RAMINFO 0x79 /* 8 bit */
|
||||
#define MUSB_LINKINFO 0x7a /* 8 bit */
|
||||
#define MUSB_VPLEN 0x7b /* 8 bit */
|
||||
#define MUSB_HS_EOF1 0x7c /* 8 bit */
|
||||
#define MUSB_FS_EOF1 0x7d /* 8 bit */
|
||||
#define MUSB_LS_EOF1 0x7e /* 8 bit */
|
||||
|
||||
/* Offsets to endpoint registers */
|
||||
#define MUSB_TXMAXP 0x00
|
||||
#define MUSB_TXCSR 0x02
|
||||
#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
|
||||
#define MUSB_RXMAXP 0x04
|
||||
#define MUSB_RXCSR 0x06
|
||||
#define MUSB_RXCOUNT 0x08
|
||||
#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
|
||||
#define MUSB_TXTYPE 0x0A
|
||||
#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
|
||||
#define MUSB_TXINTERVAL 0x0B
|
||||
#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
|
||||
#define MUSB_RXTYPE 0x0C
|
||||
#define MUSB_RXINTERVAL 0x0D
|
||||
#define MUSB_FIFOSIZE 0x0F
|
||||
#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */
|
||||
|
||||
/* Offsets to endpoint registers in indexed model (using INDEX register) */
|
||||
#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
|
||||
(0x10 + (_offset))
|
||||
|
||||
/* Offsets to endpoint registers in flat models */
|
||||
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
|
||||
(0x100 + (0x10*(_epnum)) + (_offset))
|
||||
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || \
|
||||
defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
|
||||
/* TUSB6010 EP0 configuration register is special */
|
||||
#define MUSB_TUSB_OFFSET(_epnum, _offset) \
|
||||
(0x10 + _offset)
|
||||
#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */
|
||||
#endif
|
||||
|
||||
#define MUSB_TXCSR_MODE 0x2000
|
||||
|
||||
/* "bus control"/target registers, for host side multipoint (external hubs) */
|
||||
#define MUSB_TXFUNCADDR 0x00
|
||||
#define MUSB_TXHUBADDR 0x02
|
||||
#define MUSB_TXHUBPORT 0x03
|
||||
|
||||
#define MUSB_RXFUNCADDR 0x04
|
||||
#define MUSB_RXHUBADDR 0x06
|
||||
#define MUSB_RXHUBPORT 0x07
|
||||
|
||||
#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
|
||||
(0x80 + (8*(_epnum)) + (_offset))
|
||||
|
||||
#else /* CONFIG_ARCH_SUNXI */
|
||||
|
||||
/*
|
||||
* Common USB registers
|
||||
*/
|
||||
|
||||
#define MUSB_FADDR 0x0098
|
||||
#define MUSB_POWER 0x0040
|
||||
|
||||
#define MUSB_INTRTX 0x0044
|
||||
#define MUSB_INTRRX 0x0046
|
||||
#define MUSB_INTRTXE 0x0048
|
||||
#define MUSB_INTRRXE 0x004A
|
||||
#define MUSB_INTRUSB 0x004C
|
||||
#define MUSB_INTRUSBE 0x0050
|
||||
#define MUSB_FRAME 0x0054
|
||||
#define MUSB_INDEX 0x0042
|
||||
#define MUSB_TESTMODE 0x007C
|
||||
|
||||
/* Get offset for a given FIFO from musb->mregs */
|
||||
#define MUSB_FIFO_OFFSET(epnum) (0x00 + ((epnum) * 4))
|
||||
|
||||
/*
|
||||
* Additional Control Registers
|
||||
*/
|
||||
|
||||
#define MUSB_DEVCTL 0x0041
|
||||
|
||||
/* These are always controlled through the INDEX register */
|
||||
#define MUSB_TXFIFOSZ 0x0090
|
||||
#define MUSB_RXFIFOSZ 0x0094
|
||||
#define MUSB_TXFIFOADD 0x0092
|
||||
#define MUSB_RXFIFOADD 0x0096
|
||||
|
||||
#define MUSB_EPINFO 0x0078
|
||||
#define MUSB_RAMINFO 0x0079
|
||||
#define MUSB_LINKINFO 0x007A
|
||||
#define MUSB_VPLEN 0x007B
|
||||
#define MUSB_HS_EOF1 0x007C
|
||||
#define MUSB_FS_EOF1 0x007D
|
||||
#define MUSB_LS_EOF1 0x007E
|
||||
|
||||
/* Offsets to endpoint registers */
|
||||
#define MUSB_TXMAXP 0x0080
|
||||
#define MUSB_TXCSR 0x0082
|
||||
#define MUSB_CSR0 0x0082
|
||||
#define MUSB_RXMAXP 0x0084
|
||||
#define MUSB_RXCSR 0x0086
|
||||
#define MUSB_RXCOUNT 0x0088
|
||||
#define MUSB_COUNT0 0x0088
|
||||
#define MUSB_TXTYPE 0x008C
|
||||
#define MUSB_TYPE0 0x008C
|
||||
#define MUSB_TXINTERVAL 0x008D
|
||||
#define MUSB_NAKLIMIT0 0x008D
|
||||
#define MUSB_RXTYPE 0x008E
|
||||
#define MUSB_RXINTERVAL 0x008F
|
||||
|
||||
#define MUSB_CONFIGDATA 0x00b0 /* musb_read_configdata adds 0x10 ! */
|
||||
#define MUSB_FIFOSIZE 0x0090
|
||||
|
||||
/* Offsets to endpoint registers in indexed model (using INDEX register) */
|
||||
#define MUSB_INDEXED_OFFSET(_epnum, _offset) (_offset)
|
||||
|
||||
#define MUSB_TXCSR_MODE 0x2000
|
||||
|
||||
/* "bus control"/target registers, for host side multipoint (external hubs) */
|
||||
#define MUSB_TXFUNCADDR 0x0098
|
||||
#define MUSB_TXHUBADDR 0x009A
|
||||
#define MUSB_TXHUBPORT 0x009B
|
||||
|
||||
#define MUSB_RXFUNCADDR 0x009C
|
||||
#define MUSB_RXHUBADDR 0x009E
|
||||
#define MUSB_RXHUBPORT 0x009F
|
||||
|
||||
/* Endpoint is selected with MUSB_INDEX. */
|
||||
#define MUSB_BUSCTL_OFFSET(_epnum, _offset) (_offset)
|
||||
|
||||
#endif /* CONFIG_ARCH_SUNXI */
|
||||
|
||||
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
|
||||
{
|
||||
musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
|
||||
}
|
||||
|
||||
static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off)
|
||||
{
|
||||
musb_writew(mbase, MUSB_TXFIFOADD, c_off);
|
||||
}
|
||||
|
||||
static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size)
|
||||
{
|
||||
musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
|
||||
}
|
||||
|
||||
static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
|
||||
{
|
||||
musb_writew(mbase, MUSB_RXFIFOADD, c_off);
|
||||
}
|
||||
|
||||
static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
|
||||
{
|
||||
#ifndef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
|
||||
musb_writeb(mbase, MUSB_ULPI_BUSCONTROL, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txfifosz(void __iomem *mbase)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_TXFIFOSZ);
|
||||
}
|
||||
|
||||
static inline u16 musb_read_txfifoadd(void __iomem *mbase)
|
||||
{
|
||||
return musb_readw(mbase, MUSB_TXFIFOADD);
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxfifosz(void __iomem *mbase)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_RXFIFOSZ);
|
||||
}
|
||||
|
||||
static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
|
||||
{
|
||||
return musb_readw(mbase, MUSB_RXFIFOADD);
|
||||
}
|
||||
|
||||
static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_SUNXI /* No ulpi on sunxi */
|
||||
return 0;
|
||||
#else
|
||||
return musb_readb(mbase, MUSB_ULPI_BUSCONTROL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u8 musb_read_configdata(void __iomem *mbase)
|
||||
{
|
||||
#if defined CONFIG_MACH_SUN8I_A33 || defined CONFIG_MACH_SUN8I_A83T
|
||||
/* <Sigh> allwinner saves a reg, and we need to hardcode this */
|
||||
return 0xde;
|
||||
#else
|
||||
musb_writeb(mbase, MUSB_INDEX, 0);
|
||||
return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u16 musb_read_hwvers(void __iomem *mbase)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_SUNXI
|
||||
return 0; /* Unknown version */
|
||||
#else
|
||||
return musb_readw(mbase, MUSB_HWVERS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
|
||||
{
|
||||
return (MUSB_BUSCTL_OFFSET(i, 0) + mbase);
|
||||
}
|
||||
|
||||
static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
|
||||
u8 qh_addr_reg)
|
||||
{
|
||||
musb_writeb(ep_target_regs, MUSB_RXFUNCADDR, qh_addr_reg);
|
||||
}
|
||||
|
||||
static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
|
||||
u8 qh_h_addr_reg)
|
||||
{
|
||||
musb_writeb(ep_target_regs, MUSB_RXHUBADDR, qh_h_addr_reg);
|
||||
}
|
||||
|
||||
static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
|
||||
u8 qh_h_port_reg)
|
||||
{
|
||||
musb_writeb(ep_target_regs, MUSB_RXHUBPORT, qh_h_port_reg);
|
||||
}
|
||||
|
||||
static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
|
||||
u8 qh_addr_reg)
|
||||
{
|
||||
musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
|
||||
qh_addr_reg);
|
||||
}
|
||||
|
||||
static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
|
||||
u8 qh_addr_reg)
|
||||
{
|
||||
musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
|
||||
qh_addr_reg);
|
||||
}
|
||||
|
||||
static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
|
||||
u8 qh_h_port_reg)
|
||||
{
|
||||
musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
|
||||
qh_h_port_reg);
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR));
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR));
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT));
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR));
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR));
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT));
|
||||
}
|
||||
|
||||
#else /* CONFIG_BLACKFIN */
|
||||
|
||||
#define USB_BASE USB_FADDR
|
||||
#define USB_OFFSET(reg) (reg - USB_BASE)
|
||||
|
||||
/*
|
||||
* Common USB registers
|
||||
*/
|
||||
#define MUSB_FADDR USB_OFFSET(USB_FADDR) /* 8-bit */
|
||||
#define MUSB_POWER USB_OFFSET(USB_POWER) /* 8-bit */
|
||||
#define MUSB_INTRTX USB_OFFSET(USB_INTRTX) /* 16-bit */
|
||||
#define MUSB_INTRRX USB_OFFSET(USB_INTRRX)
|
||||
#define MUSB_INTRTXE USB_OFFSET(USB_INTRTXE)
|
||||
#define MUSB_INTRRXE USB_OFFSET(USB_INTRRXE)
|
||||
#define MUSB_INTRUSB USB_OFFSET(USB_INTRUSB) /* 8 bit */
|
||||
#define MUSB_INTRUSBE USB_OFFSET(USB_INTRUSBE)/* 8 bit */
|
||||
#define MUSB_FRAME USB_OFFSET(USB_FRAME)
|
||||
#define MUSB_INDEX USB_OFFSET(USB_INDEX) /* 8 bit */
|
||||
#define MUSB_TESTMODE USB_OFFSET(USB_TESTMODE)/* 8 bit */
|
||||
|
||||
/* Get offset for a given FIFO from musb->mregs */
|
||||
#define MUSB_FIFO_OFFSET(epnum) \
|
||||
(USB_OFFSET(USB_EP0_FIFO) + ((epnum) * 8))
|
||||
|
||||
/*
|
||||
* Additional Control Registers
|
||||
*/
|
||||
|
||||
#define MUSB_DEVCTL USB_OFFSET(USB_OTG_DEV_CTL) /* 8 bit */
|
||||
|
||||
#define MUSB_LINKINFO USB_OFFSET(USB_LINKINFO)/* 8 bit */
|
||||
#define MUSB_VPLEN USB_OFFSET(USB_VPLEN) /* 8 bit */
|
||||
#define MUSB_HS_EOF1 USB_OFFSET(USB_HS_EOF1) /* 8 bit */
|
||||
#define MUSB_FS_EOF1 USB_OFFSET(USB_FS_EOF1) /* 8 bit */
|
||||
#define MUSB_LS_EOF1 USB_OFFSET(USB_LS_EOF1) /* 8 bit */
|
||||
|
||||
/* Offsets to endpoint registers */
|
||||
#define MUSB_TXMAXP 0x00
|
||||
#define MUSB_TXCSR 0x04
|
||||
#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
|
||||
#define MUSB_RXMAXP 0x08
|
||||
#define MUSB_RXCSR 0x0C
|
||||
#define MUSB_RXCOUNT 0x10
|
||||
#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
|
||||
#define MUSB_TXTYPE 0x14
|
||||
#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
|
||||
#define MUSB_TXINTERVAL 0x18
|
||||
#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
|
||||
#define MUSB_RXTYPE 0x1C
|
||||
#define MUSB_RXINTERVAL 0x20
|
||||
#define MUSB_TXCOUNT 0x28
|
||||
|
||||
/* Offsets to endpoint registers in indexed model (using INDEX register) */
|
||||
#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
|
||||
(0x40 + (_offset))
|
||||
|
||||
/* Offsets to endpoint registers in flat models */
|
||||
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
|
||||
(USB_OFFSET(USB_EP_NI0_TXMAXP) + (0x40 * (_epnum)) + (_offset))
|
||||
|
||||
/* Not implemented - HW has separate Tx/Rx FIFO */
|
||||
#define MUSB_TXCSR_MODE 0x0000
|
||||
|
||||
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val)
|
||||
{
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txfifosz(void __iomem *mbase)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u16 musb_read_txfifoadd(void __iomem *mbase)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxfifosz(void __iomem *mbase)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_configdata(void __iomem *mbase)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u16 musb_read_hwvers(void __iomem *mbase)
|
||||
{
|
||||
/*
|
||||
* This register is invisible on Blackfin, actually the MUSB
|
||||
* RTL version of Blackfin is 1.9, so just harcode its value.
|
||||
*/
|
||||
return MUSB_HWVERS_1900;
|
||||
}
|
||||
|
||||
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
|
||||
u8 qh_addr_req)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
|
||||
u8 qh_h_addr_reg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
|
||||
u8 qh_h_port_reg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
|
||||
u8 qh_addr_reg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
|
||||
u8 qh_addr_reg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
|
||||
u8 qh_h_port_reg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BLACKFIN */
|
||||
|
||||
#endif /* __MUSB_REGS_H__ */
|
||||
455
u-boot/drivers/usb/musb-new/musb_uboot.c
Normal file
455
u-boot/drivers/usb/musb-new/musb_uboot.c
Normal file
@@ -0,0 +1,455 @@
|
||||
#include <common.h>
|
||||
#include <console.h>
|
||||
#include <watchdog.h>
|
||||
#ifdef CONFIG_ARCH_SUNXI
|
||||
#include <asm/arch/usb_phy.h>
|
||||
#endif
|
||||
#include <asm/errno.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include <usb.h>
|
||||
#include "linux-compat.h"
|
||||
#include "usb-compat.h"
|
||||
#include "musb_core.h"
|
||||
#include "musb_host.h"
|
||||
#include "musb_gadget.h"
|
||||
#include "musb_uboot.h"
|
||||
|
||||
#ifdef CONFIG_USB_MUSB_HOST
|
||||
struct int_queue {
|
||||
struct usb_host_endpoint hep;
|
||||
struct urb urb;
|
||||
};
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
struct musb_host_data musb_host;
|
||||
#endif
|
||||
|
||||
static void musb_host_complete_urb(struct urb *urb)
|
||||
{
|
||||
urb->dev->status &= ~USB_ST_NOT_PROC;
|
||||
urb->dev->act_len = urb->actual_length;
|
||||
}
|
||||
|
||||
static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
|
||||
struct usb_device *dev, int endpoint_type,
|
||||
unsigned long pipe, void *buffer, int len,
|
||||
struct devrequest *setup, int interval)
|
||||
{
|
||||
int epnum = usb_pipeendpoint(pipe);
|
||||
int is_in = usb_pipein(pipe);
|
||||
|
||||
memset(urb, 0, sizeof(struct urb));
|
||||
memset(hep, 0, sizeof(struct usb_host_endpoint));
|
||||
INIT_LIST_HEAD(&hep->urb_list);
|
||||
INIT_LIST_HEAD(&urb->urb_list);
|
||||
urb->ep = hep;
|
||||
urb->complete = musb_host_complete_urb;
|
||||
urb->status = -EINPROGRESS;
|
||||
urb->dev = dev;
|
||||
urb->pipe = pipe;
|
||||
urb->transfer_buffer = buffer;
|
||||
urb->transfer_dma = (unsigned long)buffer;
|
||||
urb->transfer_buffer_length = len;
|
||||
urb->setup_packet = (unsigned char *)setup;
|
||||
|
||||
urb->ep->desc.wMaxPacketSize =
|
||||
__cpu_to_le16(is_in ? dev->epmaxpacketin[epnum] :
|
||||
dev->epmaxpacketout[epnum]);
|
||||
urb->ep->desc.bmAttributes = endpoint_type;
|
||||
urb->ep->desc.bEndpointAddress =
|
||||
(is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum;
|
||||
urb->ep->desc.bInterval = interval;
|
||||
}
|
||||
|
||||
static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
|
||||
{
|
||||
struct musb *host = hcd->hcd_priv;
|
||||
int ret;
|
||||
unsigned long timeout;
|
||||
|
||||
ret = musb_urb_enqueue(hcd, urb, 0);
|
||||
if (ret < 0) {
|
||||
printf("Failed to enqueue URB to controller\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe);
|
||||
do {
|
||||
if (ctrlc())
|
||||
return -EIO;
|
||||
host->isr(0, host);
|
||||
} while (urb->status == -EINPROGRESS &&
|
||||
get_timer(0) < timeout);
|
||||
|
||||
if (urb->status == -EINPROGRESS)
|
||||
musb_urb_dequeue(hcd, urb, -ETIME);
|
||||
|
||||
return urb->status;
|
||||
}
|
||||
|
||||
static int _musb_submit_control_msg(struct musb_host_data *host,
|
||||
struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int len, struct devrequest *setup)
|
||||
{
|
||||
construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_CONTROL,
|
||||
pipe, buffer, len, setup, 0);
|
||||
|
||||
/* Fix speed for non hub-attached devices */
|
||||
if (!usb_dev_get_parent(dev))
|
||||
dev->speed = host->host_speed;
|
||||
|
||||
return submit_urb(&host->hcd, &host->urb);
|
||||
}
|
||||
|
||||
static int _musb_submit_bulk_msg(struct musb_host_data *host,
|
||||
struct usb_device *dev, unsigned long pipe, void *buffer, int len)
|
||||
{
|
||||
construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_BULK,
|
||||
pipe, buffer, len, NULL, 0);
|
||||
return submit_urb(&host->hcd, &host->urb);
|
||||
}
|
||||
|
||||
static int _musb_submit_int_msg(struct musb_host_data *host,
|
||||
struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int len, int interval)
|
||||
{
|
||||
construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_INT, pipe,
|
||||
buffer, len, NULL, interval);
|
||||
return submit_urb(&host->hcd, &host->urb);
|
||||
}
|
||||
|
||||
static struct int_queue *_musb_create_int_queue(struct musb_host_data *host,
|
||||
struct usb_device *dev, unsigned long pipe, int queuesize,
|
||||
int elementsize, void *buffer, int interval)
|
||||
{
|
||||
struct int_queue *queue;
|
||||
int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
|
||||
|
||||
if (queuesize != 1) {
|
||||
printf("ERROR musb int-queues only support queuesize 1\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dev->int_pending & (1 << index)) {
|
||||
printf("ERROR int-urb is already pending on pipe %lx\n", pipe);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queue = malloc(sizeof(*queue));
|
||||
if (!queue)
|
||||
return NULL;
|
||||
|
||||
construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
|
||||
pipe, buffer, elementsize, NULL, interval);
|
||||
|
||||
ret = musb_urb_enqueue(&host->hcd, &queue->urb, 0);
|
||||
if (ret < 0) {
|
||||
printf("Failed to enqueue URB to controller\n");
|
||||
free(queue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->int_pending |= 1 << index;
|
||||
return queue;
|
||||
}
|
||||
|
||||
static int _musb_destroy_int_queue(struct musb_host_data *host,
|
||||
struct usb_device *dev, struct int_queue *queue)
|
||||
{
|
||||
int index = usb_pipein(queue->urb.pipe) * 16 +
|
||||
usb_pipeendpoint(queue->urb.pipe);
|
||||
|
||||
if (queue->urb.status == -EINPROGRESS)
|
||||
musb_urb_dequeue(&host->hcd, &queue->urb, -ETIME);
|
||||
|
||||
dev->int_pending &= ~(1 << index);
|
||||
free(queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *_musb_poll_int_queue(struct musb_host_data *host,
|
||||
struct usb_device *dev, struct int_queue *queue)
|
||||
{
|
||||
if (queue->urb.status != -EINPROGRESS)
|
||||
return NULL; /* URB has already completed in a prev. poll */
|
||||
|
||||
host->host->isr(0, host->host);
|
||||
|
||||
if (queue->urb.status != -EINPROGRESS)
|
||||
return queue->urb.transfer_buffer; /* Done */
|
||||
|
||||
return NULL; /* URB still pending */
|
||||
}
|
||||
|
||||
static int _musb_reset_root_port(struct musb_host_data *host,
|
||||
struct usb_device *dev)
|
||||
{
|
||||
void *mbase = host->host->mregs;
|
||||
u8 power;
|
||||
|
||||
power = musb_readb(mbase, MUSB_POWER);
|
||||
power &= 0xf0;
|
||||
musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power);
|
||||
mdelay(50);
|
||||
#ifdef CONFIG_ARCH_SUNXI
|
||||
/*
|
||||
* sunxi phy has a bug and it will wrongly detect high speed squelch
|
||||
* when clearing reset on low-speed devices, temporary disable
|
||||
* squelch detection to work around this.
|
||||
*/
|
||||
sunxi_usb_phy_enable_squelch_detect(0, 0);
|
||||
#endif
|
||||
power = musb_readb(mbase, MUSB_POWER);
|
||||
musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
|
||||
#ifdef CONFIG_ARCH_SUNXI
|
||||
sunxi_usb_phy_enable_squelch_detect(0, 1);
|
||||
#endif
|
||||
host->host->isr(0, host->host);
|
||||
host->host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
|
||||
USB_SPEED_HIGH :
|
||||
(musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
|
||||
USB_SPEED_FULL : USB_SPEED_LOW;
|
||||
mdelay((host->host_speed == USB_SPEED_LOW) ? 200 : 50);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int musb_lowlevel_init(struct musb_host_data *host)
|
||||
{
|
||||
void *mbase;
|
||||
/* USB spec says it may take up to 1 second for a device to connect */
|
||||
unsigned long timeout = get_timer(0) + 1000;
|
||||
int ret;
|
||||
|
||||
if (!host->host) {
|
||||
printf("MUSB host is not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = musb_start(host->host);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mbase = host->host->mregs;
|
||||
do {
|
||||
if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
|
||||
break;
|
||||
} while (get_timer(0) < timeout);
|
||||
if (get_timer(0) >= timeout) {
|
||||
musb_stop(host->host);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
_musb_reset_root_port(host, NULL);
|
||||
host->host->is_active = 1;
|
||||
host->hcd.hcd_priv = host->host;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
int usb_lowlevel_stop(int index)
|
||||
{
|
||||
if (!musb_host.host) {
|
||||
printf("MUSB host is not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
musb_stop(musb_host.host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int length)
|
||||
{
|
||||
return _musb_submit_bulk_msg(&musb_host, dev, pipe, buffer, length);
|
||||
}
|
||||
|
||||
int submit_control_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int length, struct devrequest *setup)
|
||||
{
|
||||
return _musb_submit_control_msg(&musb_host, dev, pipe, buffer, length, setup);
|
||||
}
|
||||
|
||||
int submit_int_msg(struct usb_device *dev, unsigned long pipe,
|
||||
void *buffer, int length, int interval)
|
||||
{
|
||||
return _musb_submit_int_msg(&musb_host, dev, pipe, buffer, length, interval);
|
||||
}
|
||||
|
||||
struct int_queue *create_int_queue(struct usb_device *dev,
|
||||
unsigned long pipe, int queuesize, int elementsize,
|
||||
void *buffer, int interval)
|
||||
{
|
||||
return _musb_create_int_queue(&musb_host, dev, pipe, queuesize, elementsize,
|
||||
buffer, interval);
|
||||
}
|
||||
|
||||
void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
|
||||
{
|
||||
return _musb_poll_int_queue(&musb_host, dev, queue);
|
||||
}
|
||||
|
||||
int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
|
||||
{
|
||||
return _musb_destroy_int_queue(&musb_host, dev, queue);
|
||||
}
|
||||
|
||||
int usb_reset_root_port(struct usb_device *dev)
|
||||
{
|
||||
return _musb_reset_root_port(&musb_host, dev);
|
||||
}
|
||||
|
||||
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
|
||||
{
|
||||
return musb_lowlevel_init(&musb_host);
|
||||
}
|
||||
#endif /* !CONFIG_DM_USB */
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
static int musb_submit_control_msg(struct udevice *dev, struct usb_device *udev,
|
||||
unsigned long pipe, void *buffer, int length,
|
||||
struct devrequest *setup)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
return _musb_submit_control_msg(host, udev, pipe, buffer, length, setup);
|
||||
}
|
||||
|
||||
static int musb_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
|
||||
unsigned long pipe, void *buffer, int length)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
return _musb_submit_bulk_msg(host, udev, pipe, buffer, length);
|
||||
}
|
||||
|
||||
static int musb_submit_int_msg(struct udevice *dev, struct usb_device *udev,
|
||||
unsigned long pipe, void *buffer, int length,
|
||||
int interval)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
return _musb_submit_int_msg(host, udev, pipe, buffer, length, interval);
|
||||
}
|
||||
|
||||
static struct int_queue *musb_create_int_queue(struct udevice *dev,
|
||||
struct usb_device *udev, unsigned long pipe, int queuesize,
|
||||
int elementsize, void *buffer, int interval)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
return _musb_create_int_queue(host, udev, pipe, queuesize, elementsize,
|
||||
buffer, interval);
|
||||
}
|
||||
|
||||
static void *musb_poll_int_queue(struct udevice *dev, struct usb_device *udev,
|
||||
struct int_queue *queue)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
return _musb_poll_int_queue(host, udev, queue);
|
||||
}
|
||||
|
||||
static int musb_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
|
||||
struct int_queue *queue)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
return _musb_destroy_int_queue(host, udev, queue);
|
||||
}
|
||||
|
||||
static int musb_reset_root_port(struct udevice *dev, struct usb_device *udev)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
return _musb_reset_root_port(host, udev);
|
||||
}
|
||||
|
||||
struct dm_usb_ops musb_usb_ops = {
|
||||
.control = musb_submit_control_msg,
|
||||
.bulk = musb_submit_bulk_msg,
|
||||
.interrupt = musb_submit_int_msg,
|
||||
.create_int_queue = musb_create_int_queue,
|
||||
.poll_int_queue = musb_poll_int_queue,
|
||||
.destroy_int_queue = musb_destroy_int_queue,
|
||||
.reset_root_port = musb_reset_root_port,
|
||||
};
|
||||
#endif /* CONFIG_DM_USB */
|
||||
#endif /* CONFIG_USB_MUSB_HOST */
|
||||
|
||||
#ifdef CONFIG_USB_MUSB_GADGET
|
||||
static struct musb *gadget;
|
||||
|
||||
int usb_gadget_handle_interrupts(int index)
|
||||
{
|
||||
WATCHDOG_RESET();
|
||||
if (!gadget || !gadget->isr)
|
||||
return -EINVAL;
|
||||
|
||||
return gadget->isr(0, gadget);
|
||||
}
|
||||
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind ||
|
||||
!driver->setup) {
|
||||
printf("bad parameter.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!gadget) {
|
||||
printf("Controller uninitialized\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = musb_gadget_start(&gadget->g, driver);
|
||||
if (ret < 0) {
|
||||
printf("gadget_start failed with %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = driver->bind(&gadget->g);
|
||||
if (ret < 0) {
|
||||
printf("bind failed with %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
if (driver->disconnect)
|
||||
driver->disconnect(&gadget->g);
|
||||
if (driver->unbind)
|
||||
driver->unbind(&gadget->g);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_USB_MUSB_GADGET */
|
||||
|
||||
int musb_register(struct musb_hdrc_platform_data *plat, void *bdata,
|
||||
void *ctl_regs)
|
||||
{
|
||||
struct musb **musbp;
|
||||
|
||||
switch (plat->mode) {
|
||||
#if defined(CONFIG_USB_MUSB_HOST) && !defined(CONFIG_DM_USB)
|
||||
case MUSB_HOST:
|
||||
musbp = &musb_host.host;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_MUSB_GADGET
|
||||
case MUSB_PERIPHERAL:
|
||||
musbp = &gadget;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*musbp = musb_init_controller(plat, (struct device *)bdata, ctl_regs);
|
||||
if (!musbp) {
|
||||
printf("Failed to init the controller\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
u-boot/drivers/usb/musb-new/musb_uboot.h
Normal file
28
u-boot/drivers/usb/musb-new/musb_uboot.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* MUSB OTG driver u-boot specific functions
|
||||
*
|
||||
* Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#ifndef __MUSB_UBOOT_H__
|
||||
#define __MUSB_UBOOT_H__
|
||||
|
||||
#include <usb.h>
|
||||
#include "linux-compat.h"
|
||||
#include "usb-compat.h"
|
||||
#include "musb_core.h"
|
||||
|
||||
struct musb_host_data {
|
||||
struct musb *host;
|
||||
struct usb_hcd hcd;
|
||||
enum usb_device_speed host_speed;
|
||||
struct usb_host_endpoint hep;
|
||||
struct urb urb;
|
||||
};
|
||||
|
||||
extern struct dm_usb_ops musb_usb_ops;
|
||||
|
||||
int musb_lowlevel_init(struct musb_host_data *host);
|
||||
|
||||
#endif
|
||||
644
u-boot/drivers/usb/musb-new/omap2430.c
Normal file
644
u-boot/drivers/usb/musb-new/omap2430.c
Normal file
@@ -0,0 +1,644 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 by Texas Instruments
|
||||
* Some code has been taken from tusb6010.c
|
||||
* Copyrights for that are attributable to:
|
||||
* Copyright (C) 2006 Nokia Corporation
|
||||
* Tony Lindgren <tony@atomide.com>
|
||||
*
|
||||
* This file is part of the Inventra Controller Driver for Linux.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/usb/musb-omap.h>
|
||||
#else
|
||||
#include <common.h>
|
||||
#include <asm/omap_common.h>
|
||||
#include <asm/omap_musb.h>
|
||||
#include <twl4030.h>
|
||||
#include <twl6030.h>
|
||||
#include "linux-compat.h"
|
||||
#endif
|
||||
|
||||
#include "musb_core.h"
|
||||
#include "omap2430.h"
|
||||
|
||||
#ifndef __UBOOT__
|
||||
struct omap2430_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
enum omap_musb_vbus_id_status status;
|
||||
struct work_struct omap_musb_mailbox_work;
|
||||
};
|
||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
||||
|
||||
struct omap2430_glue *_glue;
|
||||
|
||||
static struct timer_list musb_idle_timer;
|
||||
|
||||
static void musb_do_idle(unsigned long _musb)
|
||||
{
|
||||
struct musb *musb = (void *)_musb;
|
||||
unsigned long flags;
|
||||
u8 power;
|
||||
u8 devctl;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
switch (musb->xceiv->state) {
|
||||
case OTG_STATE_A_WAIT_BCON:
|
||||
|
||||
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_SUSPEND:
|
||||
/* finish RESUME signaling? */
|
||||
if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
|
||||
power = musb_readb(musb->mregs, MUSB_POWER);
|
||||
power &= ~MUSB_POWER_RESUME;
|
||||
dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power);
|
||||
musb_writeb(musb->mregs, MUSB_POWER, power);
|
||||
musb->is_active = 1;
|
||||
musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
|
||||
| MUSB_PORT_STAT_RESUME);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case OTG_STATE_A_HOST:
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE)
|
||||
musb->xceiv->state = OTG_STATE_B_IDLE;
|
||||
else
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
|
||||
static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
|
||||
static unsigned long last_timer;
|
||||
|
||||
if (timeout == 0)
|
||||
timeout = default_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))) {
|
||||
dev_dbg(musb->controller, "%s active, deleting timer\n",
|
||||
otg_state_string(musb->xceiv->state));
|
||||
del_timer(&musb_idle_timer);
|
||||
last_timer = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_after(last_timer, timeout)) {
|
||||
if (!timer_pending(&musb_idle_timer))
|
||||
last_timer = timeout;
|
||||
else {
|
||||
dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
last_timer = timeout;
|
||||
|
||||
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
(unsigned long)jiffies_to_msecs(timeout - jiffies));
|
||||
mod_timer(&musb_idle_timer, timeout);
|
||||
}
|
||||
|
||||
static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
struct usb_otg *otg = musb->xceiv->otg;
|
||||
u8 devctl;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
|
||||
int ret = 1;
|
||||
/* HDRC controls CPEN, but beware current surges during device
|
||||
* connect. They can trigger transient overcurrent conditions
|
||||
* that must be ignored.
|
||||
*/
|
||||
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
|
||||
if (is_on) {
|
||||
if (musb->xceiv->state == OTG_STATE_A_IDLE) {
|
||||
/* start the session */
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
/*
|
||||
* Wait for the musb to set as A device to enable the
|
||||
* VBUS
|
||||
*/
|
||||
while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
|
||||
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(musb->controller,
|
||||
"configured as A device timeout");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && otg->set_vbus)
|
||||
otg_set_vbus(otg, 1);
|
||||
} else {
|
||||
musb->is_active = 1;
|
||||
otg->default_a = 1;
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
MUSB_HST_MODE(musb);
|
||||
}
|
||||
} else {
|
||||
musb->is_active = 0;
|
||||
|
||||
/* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and
|
||||
* jumping right to B_IDLE...
|
||||
*/
|
||||
|
||||
otg->default_a = 0;
|
||||
musb->xceiv->state = OTG_STATE_B_IDLE;
|
||||
devctl &= ~MUSB_DEVCTL_SESSION;
|
||||
|
||||
MUSB_DEV_MODE(musb);
|
||||
}
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
|
||||
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
|
||||
/* otg %3x conf %08x prcm %08x */ "\n",
|
||||
otg_state_string(musb->xceiv->state),
|
||||
musb_readb(musb->mregs, MUSB_DEVCTL));
|
||||
}
|
||||
|
||||
static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void omap2430_low_level_exit(struct musb *musb)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
/* in any role */
|
||||
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
l |= ENABLEFORCE; /* enable MSTANDBY */
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
|
||||
}
|
||||
|
||||
static inline void omap2430_low_level_init(struct musb *musb)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
l &= ~ENABLEFORCE; /* disable MSTANDBY */
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
|
||||
{
|
||||
struct omap2430_glue *glue = _glue;
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
glue->status = status;
|
||||
if (!musb) {
|
||||
dev_err(glue->dev, "musb core is not yet ready\n");
|
||||
return;
|
||||
}
|
||||
|
||||
schedule_work(&glue->omap_musb_mailbox_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omap_musb_mailbox);
|
||||
|
||||
static void omap_musb_set_mailbox(struct omap2430_glue *glue)
|
||||
{
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *pdata = dev->platform_data;
|
||||
struct omap_musb_board_data *data = pdata->board_data;
|
||||
struct usb_otg *otg = musb->xceiv->otg;
|
||||
|
||||
switch (glue->status) {
|
||||
case OMAP_MUSB_ID_GROUND:
|
||||
dev_dbg(dev, "ID GND\n");
|
||||
|
||||
otg->default_a = true;
|
||||
musb->xceiv->state = OTG_STATE_A_IDLE;
|
||||
musb->xceiv->last_event = USB_EVENT_ID;
|
||||
if (!is_otg_enabled(musb) || musb->gadget_driver) {
|
||||
pm_runtime_get_sync(dev);
|
||||
usb_phy_init(musb->xceiv);
|
||||
omap2430_musb_set_vbus(musb, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case OMAP_MUSB_VBUS_VALID:
|
||||
dev_dbg(dev, "VBUS Connect\n");
|
||||
|
||||
otg->default_a = false;
|
||||
musb->xceiv->state = OTG_STATE_B_IDLE;
|
||||
musb->xceiv->last_event = USB_EVENT_VBUS;
|
||||
if (musb->gadget_driver)
|
||||
pm_runtime_get_sync(dev);
|
||||
usb_phy_init(musb->xceiv);
|
||||
break;
|
||||
|
||||
case OMAP_MUSB_ID_FLOAT:
|
||||
case OMAP_MUSB_VBUS_OFF:
|
||||
dev_dbg(dev, "VBUS Disconnect\n");
|
||||
|
||||
musb->xceiv->last_event = USB_EVENT_NONE;
|
||||
if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
|
||||
if (musb->gadget_driver) {
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
}
|
||||
|
||||
if (data->interface_type == MUSB_INTERFACE_UTMI) {
|
||||
if (musb->xceiv->otg->set_vbus)
|
||||
otg_set_vbus(musb->xceiv->otg, 0);
|
||||
}
|
||||
usb_phy_shutdown(musb->xceiv);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "ID float\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
|
||||
{
|
||||
struct omap2430_glue *glue = container_of(mailbox_work,
|
||||
struct omap2430_glue, omap_musb_mailbox_work);
|
||||
omap_musb_set_mailbox(glue);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int omap2430_musb_init(struct musb *musb)
|
||||
{
|
||||
u32 l;
|
||||
int status = 0;
|
||||
unsigned long int start;
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
#else
|
||||
struct omap_musb_board_data *data =
|
||||
(struct omap_musb_board_data *)musb->controller;
|
||||
#endif
|
||||
|
||||
/* Reset the controller */
|
||||
musb_writel(musb->mregs, OTG_SYSCONFIG, SOFTRST);
|
||||
|
||||
start = get_timer(0);
|
||||
|
||||
while (1) {
|
||||
l = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
if ((l & SOFTRST) == 0)
|
||||
break;
|
||||
|
||||
if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
|
||||
dev_err(musb->controller, "MUSB reset is taking too long\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* 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 = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(musb->xceiv)) {
|
||||
pr_err("HS USB OTG: no transceiver configured\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
status = pm_runtime_get_sync(dev);
|
||||
if (status < 0) {
|
||||
dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
|
||||
goto err1;
|
||||
}
|
||||
#endif
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_INTERFSEL);
|
||||
|
||||
if (data->interface_type == MUSB_INTERFACE_UTMI) {
|
||||
/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
|
||||
l &= ~ULPI_12PIN; /* Disable ULPI */
|
||||
l |= UTMI_8BIT; /* Enable UTMI */
|
||||
} else {
|
||||
l |= ULPI_12PIN;
|
||||
}
|
||||
|
||||
musb_writel(musb->mregs, OTG_INTERFSEL, l);
|
||||
|
||||
pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
|
||||
"sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n",
|
||||
musb_readl(musb->mregs, OTG_REVISION),
|
||||
musb_readl(musb->mregs, OTG_SYSCONFIG),
|
||||
musb_readl(musb->mregs, OTG_SYSSTATUS),
|
||||
musb_readl(musb->mregs, OTG_INTERFSEL),
|
||||
musb_readl(musb->mregs, OTG_SIMENABLE));
|
||||
|
||||
#ifndef __UBOOT__
|
||||
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
|
||||
|
||||
if (glue->status != OMAP_MUSB_UNKNOWN)
|
||||
omap_musb_set_mailbox(glue);
|
||||
|
||||
pm_runtime_put_noidle(musb->controller);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static void omap2430_musb_enable(struct musb *musb)
|
||||
#else
|
||||
static int omap2430_musb_enable(struct musb *musb)
|
||||
#endif
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
u8 devctl;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
|
||||
struct device *dev = musb->controller;
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
|
||||
struct musb_hdrc_platform_data *pdata = dev->platform_data;
|
||||
struct omap_musb_board_data *data = pdata->board_data;
|
||||
|
||||
switch (glue->status) {
|
||||
|
||||
case OMAP_MUSB_ID_GROUND:
|
||||
usb_phy_init(musb->xceiv);
|
||||
if (data->interface_type != MUSB_INTERFACE_UTMI)
|
||||
break;
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
/* start the session */
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
while (musb_readb(musb->mregs, MUSB_DEVCTL) &
|
||||
MUSB_DEVCTL_BDEVICE) {
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(dev, "configured as A device timeout");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OMAP_MUSB_VBUS_VALID:
|
||||
usb_phy_init(musb->xceiv);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
#ifdef CONFIG_TWL4030_USB
|
||||
if (twl4030_usb_ulpi_init()) {
|
||||
serial_printf("ERROR: %s Could not initialize PHY\n",
|
||||
__PRETTY_FUNCTION__);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TWL6030_POWER
|
||||
twl6030_usb_device_settings();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP4430
|
||||
u32 *usbotghs_control = (u32 *)((*ctrl)->control_usbotghs_ctrl);
|
||||
*usbotghs_control = USBOTGHS_CONTROL_AVALID |
|
||||
USBOTGHS_CONTROL_VBUSVALID | USBOTGHS_CONTROL_IDDIG;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void omap2430_musb_disable(struct musb *musb)
|
||||
{
|
||||
#ifndef __UBOOT__
|
||||
struct device *dev = musb->controller;
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (glue->status != OMAP_MUSB_UNKNOWN)
|
||||
usb_phy_shutdown(musb->xceiv);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int omap2430_musb_exit(struct musb *musb)
|
||||
{
|
||||
del_timer_sync(&musb_idle_timer);
|
||||
|
||||
omap2430_low_level_exit(musb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static const struct musb_platform_ops omap2430_ops = {
|
||||
#else
|
||||
const struct musb_platform_ops omap2430_ops = {
|
||||
#endif
|
||||
.init = omap2430_musb_init,
|
||||
.exit = omap2430_musb_exit,
|
||||
|
||||
#ifndef __UBOOT__
|
||||
.set_mode = omap2430_musb_set_mode,
|
||||
.try_idle = omap2430_musb_try_idle,
|
||||
|
||||
.set_vbus = omap2430_musb_set_vbus,
|
||||
#endif
|
||||
|
||||
.enable = omap2430_musb_enable,
|
||||
.disable = omap2430_musb_disable,
|
||||
};
|
||||
|
||||
#ifndef __UBOOT__
|
||||
static u64 omap2430_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __devinit omap2430_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct omap2430_glue *glue;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &omap2430_dmamask;
|
||||
musb->dev.coherent_dma_mask = omap2430_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->status = OMAP_MUSB_UNKNOWN;
|
||||
|
||||
pdata->platform_ops = &omap2430_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
/*
|
||||
* REVISIT if we ever have two instances of the wrapper, we will be
|
||||
* in big trouble
|
||||
*/
|
||||
_glue = glue;
|
||||
|
||||
INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
platform_device_put(musb);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit omap2430_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap2430_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
cancel_work_sync(&glue->omap_musb_mailbox_work);
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int omap2430_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
if (musb) {
|
||||
musb->context.otg_interfsel = musb_readl(musb->mregs,
|
||||
OTG_INTERFSEL);
|
||||
|
||||
omap2430_low_level_exit(musb);
|
||||
usb_phy_set_suspend(musb->xceiv, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap2430_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
if (musb) {
|
||||
omap2430_low_level_init(musb);
|
||||
musb_writel(musb->mregs, OTG_INTERFSEL,
|
||||
musb->context.otg_interfsel);
|
||||
|
||||
usb_phy_set_suspend(musb->xceiv, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops omap2430_pm_ops = {
|
||||
.runtime_suspend = omap2430_runtime_suspend,
|
||||
.runtime_resume = omap2430_runtime_resume,
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&omap2430_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver omap2430_driver = {
|
||||
.probe = omap2430_probe,
|
||||
.remove = __devexit_p(omap2430_remove),
|
||||
.driver = {
|
||||
.name = "musb-omap2430",
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init omap2430_init(void)
|
||||
{
|
||||
return platform_driver_register(&omap2430_driver);
|
||||
}
|
||||
subsys_initcall(omap2430_init);
|
||||
|
||||
static void __exit omap2430_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&omap2430_driver);
|
||||
}
|
||||
module_exit(omap2430_exit);
|
||||
#endif
|
||||
61
u-boot/drivers/usb/musb-new/omap2430.h
Normal file
61
u-boot/drivers/usb/musb-new/omap2430.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
#ifndef __MUSB_OMAP243X_H__
|
||||
#define __MUSB_OMAP243X_H__
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <plat/usb.h>
|
||||
#else
|
||||
#undef RESETDONE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OMAP2430-specific definitions
|
||||
*/
|
||||
|
||||
#define OTG_REVISION 0x400
|
||||
|
||||
#define OTG_SYSCONFIG 0x404
|
||||
# define MIDLEMODE 12 /* bit position */
|
||||
# define FORCESTDBY (0 << MIDLEMODE)
|
||||
# define NOSTDBY (1 << MIDLEMODE)
|
||||
# define SMARTSTDBY (2 << MIDLEMODE)
|
||||
|
||||
# define SIDLEMODE 3 /* bit position */
|
||||
# define FORCEIDLE (0 << SIDLEMODE)
|
||||
# define NOIDLE (1 << SIDLEMODE)
|
||||
# define SMARTIDLE (2 << SIDLEMODE)
|
||||
|
||||
# define ENABLEWAKEUP (1 << 2)
|
||||
# define SOFTRST (1 << 1)
|
||||
# define AUTOIDLE (1 << 0)
|
||||
|
||||
#define OTG_SYSSTATUS 0x408
|
||||
# define RESETDONE (1 << 0)
|
||||
|
||||
#define OTG_INTERFSEL 0x40c
|
||||
# define EXTCP (1 << 2)
|
||||
# define PHYSEL 0 /* bit position */
|
||||
# define UTMI_8BIT (0 << PHYSEL)
|
||||
# define ULPI_12PIN (1 << PHYSEL)
|
||||
# define ULPI_8PIN (2 << PHYSEL)
|
||||
|
||||
#define OTG_SIMENABLE 0x410
|
||||
# define TM1 (1 << 0)
|
||||
|
||||
#define OTG_FORCESTDBY 0x414
|
||||
# define ENABLEFORCE (1 << 0)
|
||||
|
||||
/*
|
||||
* OMAP4-specific definitions
|
||||
*/
|
||||
|
||||
#define USBOTGHS_CONTROL_AVALID (1 << 0)
|
||||
#define USBOTGHS_CONTROL_VBUSVALID (1 << 2)
|
||||
#define USBOTGHS_CONTROL_IDDIG (1 << 4)
|
||||
|
||||
#endif /* __MUSB_OMAP243X_H__ */
|
||||
288
u-boot/drivers/usb/musb-new/pic32.c
Normal file
288
u-boot/drivers/usb/musb-new/pic32.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Microchip PIC32 MUSB "glue layer"
|
||||
*
|
||||
* Copyright (C) 2015, Microchip Technology Inc.
|
||||
* Cristian Birsan <cristian.birsan@microchip.com>
|
||||
* Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Based on the dsps "glue layer" code.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/usb/musb.h>
|
||||
#include "linux-compat.h"
|
||||
#include "musb_core.h"
|
||||
#include "musb_uboot.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define PIC32_TX_EP_MASK 0x0f /* EP0 + 7 Tx EPs */
|
||||
#define PIC32_RX_EP_MASK 0x0e /* 7 Rx EPs */
|
||||
|
||||
#define MUSB_SOFTRST 0x7f
|
||||
#define MUSB_SOFTRST_NRST BIT(0)
|
||||
#define MUSB_SOFTRST_NRSTX BIT(1)
|
||||
|
||||
#define USBCRCON 0
|
||||
#define USBCRCON_USBWKUPEN BIT(0) /* Enable Wakeup Interrupt */
|
||||
#define USBCRCON_USBRIE BIT(1) /* Enable Remote resume Interrupt */
|
||||
#define USBCRCON_USBIE BIT(2) /* Enable USB General interrupt */
|
||||
#define USBCRCON_SENDMONEN BIT(3) /* Enable Session End VBUS monitoring */
|
||||
#define USBCRCON_BSVALMONEN BIT(4) /* Enable B-Device VBUS monitoring */
|
||||
#define USBCRCON_ASVALMONEN BIT(5) /* Enable A-Device VBUS monitoring */
|
||||
#define USBCRCON_VBUSMONEN BIT(6) /* Enable VBUS monitoring */
|
||||
#define USBCRCON_PHYIDEN BIT(7) /* PHY ID monitoring enable */
|
||||
#define USBCRCON_USBIDVAL BIT(8) /* USB ID value */
|
||||
#define USBCRCON_USBIDOVEN BIT(9) /* USB ID override enable */
|
||||
#define USBCRCON_USBWK BIT(24) /* USB Wakeup Status */
|
||||
#define USBCRCON_USBRF BIT(25) /* USB Resume Status */
|
||||
#define USBCRCON_USBIF BIT(26) /* USB General Interrupt Status */
|
||||
|
||||
/* PIC32 controller data */
|
||||
struct pic32_musb_data {
|
||||
struct musb_host_data mdata;
|
||||
struct device dev;
|
||||
void __iomem *musb_glue;
|
||||
};
|
||||
|
||||
#define to_pic32_musb_data(d) \
|
||||
container_of(d, struct pic32_musb_data, dev)
|
||||
|
||||
static void pic32_musb_disable(struct musb *musb)
|
||||
{
|
||||
/* no way to shut the controller */
|
||||
}
|
||||
|
||||
static int pic32_musb_enable(struct musb *musb)
|
||||
{
|
||||
/* soft reset by NRSTx */
|
||||
musb_writeb(musb->mregs, MUSB_SOFTRST, MUSB_SOFTRST_NRSTX);
|
||||
/* set mode */
|
||||
musb_platform_set_mode(musb, musb->board_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t pic32_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 epintr, usbintr;
|
||||
|
||||
/* ack usb core interrupts */
|
||||
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
|
||||
if (musb->int_usb)
|
||||
musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
|
||||
|
||||
/* ack endpoint interrupts */
|
||||
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX) & PIC32_RX_EP_MASK;
|
||||
if (musb->int_rx)
|
||||
musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
|
||||
|
||||
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX) & PIC32_TX_EP_MASK;
|
||||
if (musb->int_tx)
|
||||
musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
|
||||
|
||||
/* drop spurious RX and TX if device is disconnected */
|
||||
if (musb->int_usb & MUSB_INTR_DISCONNECT) {
|
||||
musb->int_tx = 0;
|
||||
musb->int_rx = 0;
|
||||
}
|
||||
|
||||
if (musb->int_tx || musb->int_rx || musb->int_usb)
|
||||
ret = musb_interrupt(musb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pic32_musb_set_mode(struct musb *musb, u8 mode)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct pic32_musb_data *pdata = to_pic32_musb_data(dev);
|
||||
|
||||
switch (mode) {
|
||||
case MUSB_HOST:
|
||||
clrsetbits_le32(pdata->musb_glue + USBCRCON,
|
||||
USBCRCON_USBIDVAL, USBCRCON_USBIDOVEN);
|
||||
break;
|
||||
case MUSB_PERIPHERAL:
|
||||
setbits_le32(pdata->musb_glue + USBCRCON,
|
||||
USBCRCON_USBIDVAL | USBCRCON_USBIDOVEN);
|
||||
break;
|
||||
case MUSB_OTG:
|
||||
dev_err(dev, "support for OTG is unimplemented\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported mode %d\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_musb_init(struct musb *musb)
|
||||
{
|
||||
struct pic32_musb_data *pdata = to_pic32_musb_data(musb->controller);
|
||||
u32 ctrl, hwvers;
|
||||
u8 power;
|
||||
|
||||
/* Returns zero if not clocked */
|
||||
hwvers = musb_read_hwvers(musb->mregs);
|
||||
if (!hwvers)
|
||||
return -ENODEV;
|
||||
|
||||
/* Reset the musb */
|
||||
power = musb_readb(musb->mregs, MUSB_POWER);
|
||||
power = power | MUSB_POWER_RESET;
|
||||
musb_writeb(musb->mregs, MUSB_POWER, power);
|
||||
mdelay(100);
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
power = power & ~MUSB_POWER_RESET;
|
||||
musb_writeb(musb->mregs, MUSB_POWER, power);
|
||||
|
||||
musb->isr = pic32_interrupt;
|
||||
|
||||
ctrl = USBCRCON_USBIF | USBCRCON_USBRF |
|
||||
USBCRCON_USBWK | USBCRCON_USBIDOVEN |
|
||||
USBCRCON_PHYIDEN | USBCRCON_USBIE |
|
||||
USBCRCON_USBRIE | USBCRCON_USBWKUPEN |
|
||||
USBCRCON_VBUSMONEN;
|
||||
writel(ctrl, pdata->musb_glue + USBCRCON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PIC32 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, rem = len % 4;
|
||||
|
||||
/* USB stack ensures dst is always 32bit aligned. */
|
||||
readsl(fifo, dst, len / 4);
|
||||
if (rem) {
|
||||
dst += len & ~0x03;
|
||||
val = musb_readl(fifo, 0);
|
||||
memcpy(dst, &val, rem);
|
||||
}
|
||||
}
|
||||
|
||||
const struct musb_platform_ops pic32_musb_ops = {
|
||||
.init = pic32_musb_init,
|
||||
.set_mode = pic32_musb_set_mode,
|
||||
.disable = pic32_musb_disable,
|
||||
.enable = pic32_musb_enable,
|
||||
};
|
||||
|
||||
/* PIC32 default FIFO config - fits in 8KB */
|
||||
static struct musb_fifo_cfg pic32_musb_fifo_config[] = {
|
||||
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, },
|
||||
};
|
||||
|
||||
static struct musb_hdrc_config pic32_musb_config = {
|
||||
.fifo_cfg = pic32_musb_fifo_config,
|
||||
.fifo_cfg_size = ARRAY_SIZE(pic32_musb_fifo_config),
|
||||
.multipoint = 1,
|
||||
.dyn_fifo = 1,
|
||||
.num_eps = 8,
|
||||
.ram_bits = 11,
|
||||
};
|
||||
|
||||
/* PIC32 has one MUSB controller which can be host or gadget */
|
||||
static struct musb_hdrc_platform_data pic32_musb_plat = {
|
||||
.mode = MUSB_HOST,
|
||||
.config = &pic32_musb_config,
|
||||
.power = 250, /* 500mA */
|
||||
.platform_ops = &pic32_musb_ops,
|
||||
};
|
||||
|
||||
static int musb_usb_probe(struct udevice *dev)
|
||||
{
|
||||
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
|
||||
struct pic32_musb_data *pdata = dev_get_priv(dev);
|
||||
struct musb_host_data *mdata = &pdata->mdata;
|
||||
struct fdt_resource mc, glue;
|
||||
void *fdt = (void *)gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
void __iomem *mregs;
|
||||
int ret;
|
||||
|
||||
priv->desc_before_addr = true;
|
||||
|
||||
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
|
||||
"mc", &mc);
|
||||
if (ret < 0) {
|
||||
printf("pic32-musb: resource \"mc\" not found\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
|
||||
"control", &glue);
|
||||
if (ret < 0) {
|
||||
printf("pic32-musb: resource \"control\" not found\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mregs = ioremap(mc.start, fdt_resource_size(&mc));
|
||||
pdata->musb_glue = ioremap(glue.start, fdt_resource_size(&glue));
|
||||
|
||||
/* init controller */
|
||||
#ifdef CONFIG_USB_MUSB_HOST
|
||||
mdata->host = musb_init_controller(&pic32_musb_plat,
|
||||
&pdata->dev, mregs);
|
||||
if (!mdata->host)
|
||||
return -EIO;
|
||||
|
||||
ret = musb_lowlevel_init(mdata);
|
||||
#else
|
||||
pic32_musb_plat.mode = MUSB_PERIPHERAL;
|
||||
ret = musb_register(&pic32_musb_plat, &pdata->dev, mregs);
|
||||
#endif
|
||||
if (ret == 0)
|
||||
printf("PIC32 MUSB OTG\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int musb_usb_remove(struct udevice *dev)
|
||||
{
|
||||
struct pic32_musb_data *pdata = dev_get_priv(dev);
|
||||
|
||||
musb_stop(pdata->mdata.host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id pic32_musb_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-usb" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(usb_musb) = {
|
||||
.name = "pic32-musb",
|
||||
.id = UCLASS_USB,
|
||||
.of_match = pic32_musb_ids,
|
||||
.probe = musb_usb_probe,
|
||||
.remove = musb_usb_remove,
|
||||
#ifdef CONFIG_USB_MUSB_HOST
|
||||
.ops = &musb_usb_ops,
|
||||
#endif
|
||||
.platdata_auto_alloc_size = sizeof(struct usb_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct pic32_musb_data),
|
||||
};
|
||||
382
u-boot/drivers/usb/musb-new/sunxi.c
Normal file
382
u-boot/drivers/usb/musb-new/sunxi.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Allwinner SUNXI "glue layer"
|
||||
*
|
||||
* Copyright © 2015 Hans de Goede <hdegoede@redhat.com>
|
||||
* Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||
*
|
||||
* Based on the sw_usb "Allwinner OTG Dual Role Controller" code.
|
||||
* Copyright 2007-2012 (C) Allwinner Technology Co., Ltd.
|
||||
* javen <javen@allwinnertech.com>
|
||||
*
|
||||
* Based on the DA8xx "glue layer" code.
|
||||
* Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
|
||||
* Copyright (C) 2005-2006 by Texas Instruments
|
||||
*
|
||||
* This file is part of the Inventra Controller Driver for Linux.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/usb_phy.h>
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/root.h>
|
||||
#include <linux/usb/musb.h>
|
||||
#include "linux-compat.h"
|
||||
#include "musb_core.h"
|
||||
#include "musb_uboot.h"
|
||||
|
||||
/******************************************************************************
|
||||
******************************************************************************
|
||||
* From the Allwinner driver
|
||||
******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* From include/sunxi_usb_bsp.h
|
||||
******************************************************************************/
|
||||
|
||||
/* reg offsets */
|
||||
#define USBC_REG_o_ISCR 0x0400
|
||||
#define USBC_REG_o_PHYCTL 0x0404
|
||||
#define USBC_REG_o_PHYBIST 0x0408
|
||||
#define USBC_REG_o_PHYTUNE 0x040c
|
||||
|
||||
#define USBC_REG_o_VEND0 0x0043
|
||||
|
||||
/* Interface Status and Control */
|
||||
#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30
|
||||
#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29
|
||||
#define USBC_BP_ISCR_EXT_ID_STATUS 28
|
||||
#define USBC_BP_ISCR_EXT_DM_STATUS 27
|
||||
#define USBC_BP_ISCR_EXT_DP_STATUS 26
|
||||
#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25
|
||||
#define USBC_BP_ISCR_MERGED_ID_STATUS 24
|
||||
|
||||
#define USBC_BP_ISCR_ID_PULLUP_EN 17
|
||||
#define USBC_BP_ISCR_DPDM_PULLUP_EN 16
|
||||
#define USBC_BP_ISCR_FORCE_ID 14
|
||||
#define USBC_BP_ISCR_FORCE_VBUS_VALID 12
|
||||
#define USBC_BP_ISCR_VBUS_VALID_SRC 10
|
||||
|
||||
#define USBC_BP_ISCR_HOSC_EN 7
|
||||
#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6
|
||||
#define USBC_BP_ISCR_ID_CHANGE_DETECT 5
|
||||
#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4
|
||||
#define USBC_BP_ISCR_IRQ_ENABLE 3
|
||||
#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2
|
||||
#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1
|
||||
#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0
|
||||
|
||||
/******************************************************************************
|
||||
* From usbc/usbc.c
|
||||
******************************************************************************/
|
||||
|
||||
static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val)
|
||||
{
|
||||
u32 temp = reg_val;
|
||||
|
||||
temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
|
||||
temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
|
||||
temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
static void USBC_EnableIdPullUp(__iomem void *base)
|
||||
{
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = musb_readl(base, USBC_REG_o_ISCR);
|
||||
reg_val |= (1 << USBC_BP_ISCR_ID_PULLUP_EN);
|
||||
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
|
||||
musb_writel(base, USBC_REG_o_ISCR, reg_val);
|
||||
}
|
||||
|
||||
static void USBC_EnableDpDmPullUp(__iomem void *base)
|
||||
{
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = musb_readl(base, USBC_REG_o_ISCR);
|
||||
reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
|
||||
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
|
||||
musb_writel(base, USBC_REG_o_ISCR, reg_val);
|
||||
}
|
||||
|
||||
static void USBC_ForceIdToLow(__iomem void *base)
|
||||
{
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = musb_readl(base, USBC_REG_o_ISCR);
|
||||
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
|
||||
reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
|
||||
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
|
||||
musb_writel(base, USBC_REG_o_ISCR, reg_val);
|
||||
}
|
||||
|
||||
static void USBC_ForceIdToHigh(__iomem void *base)
|
||||
{
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = musb_readl(base, USBC_REG_o_ISCR);
|
||||
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
|
||||
reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
|
||||
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
|
||||
musb_writel(base, USBC_REG_o_ISCR, reg_val);
|
||||
}
|
||||
|
||||
static void USBC_ForceVbusValidToLow(__iomem void *base)
|
||||
{
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = musb_readl(base, USBC_REG_o_ISCR);
|
||||
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
|
||||
reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID);
|
||||
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
|
||||
musb_writel(base, USBC_REG_o_ISCR, reg_val);
|
||||
}
|
||||
|
||||
static void USBC_ForceVbusValidToHigh(__iomem void *base)
|
||||
{
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = musb_readl(base, USBC_REG_o_ISCR);
|
||||
reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
|
||||
reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
|
||||
reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
|
||||
musb_writel(base, USBC_REG_o_ISCR, reg_val);
|
||||
}
|
||||
|
||||
static void USBC_ConfigFIFO_Base(void)
|
||||
{
|
||||
u32 reg_value;
|
||||
|
||||
/* config usb fifo, 8kb mode */
|
||||
reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
|
||||
reg_value &= ~(0x03 << 0);
|
||||
reg_value |= (1 << 0);
|
||||
writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Needed for the DFU polling magic
|
||||
******************************************************************************/
|
||||
|
||||
static u8 last_int_usb;
|
||||
|
||||
bool dfu_usb_get_reset(void)
|
||||
{
|
||||
return !!(last_int_usb & MUSB_INTR_RESET);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* MUSB Glue code
|
||||
******************************************************************************/
|
||||
|
||||
static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
|
||||
{
|
||||
struct musb *musb = __hci;
|
||||
irqreturn_t retval = IRQ_NONE;
|
||||
|
||||
/* read and flush interrupts */
|
||||
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
|
||||
last_int_usb = musb->int_usb;
|
||||
if (musb->int_usb)
|
||||
musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
|
||||
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
|
||||
if (musb->int_tx)
|
||||
musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
|
||||
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
|
||||
if (musb->int_rx)
|
||||
musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
|
||||
|
||||
if (musb->int_usb || musb->int_tx || musb->int_rx)
|
||||
retval |= musb_interrupt(musb);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* musb_core does not call enable / disable in a balanced manner <sigh> */
|
||||
static bool enabled = false;
|
||||
static struct musb *sunxi_musb;
|
||||
|
||||
static int sunxi_musb_enable(struct musb *musb)
|
||||
{
|
||||
pr_debug("%s():\n", __func__);
|
||||
|
||||
musb_ep_select(musb->mregs, 0);
|
||||
musb_writeb(musb->mregs, MUSB_FADDR, 0);
|
||||
|
||||
if (enabled)
|
||||
return 0;
|
||||
|
||||
/* select PIO mode */
|
||||
musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
|
||||
|
||||
if (is_host_enabled(musb)) {
|
||||
int id = sunxi_usb_phy_id_detect(0);
|
||||
|
||||
if (id == 1 && sunxi_usb_phy_power_is_on(0))
|
||||
sunxi_usb_phy_power_off(0);
|
||||
|
||||
if (!sunxi_usb_phy_power_is_on(0)) {
|
||||
int vbus = sunxi_usb_phy_vbus_detect(0);
|
||||
if (vbus == 1) {
|
||||
printf("A charger is plugged into the OTG: ");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == 1) {
|
||||
printf("No host cable detected: ");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!sunxi_usb_phy_power_is_on(0))
|
||||
sunxi_usb_phy_power_on(0);
|
||||
}
|
||||
|
||||
USBC_ForceVbusValidToHigh(musb->mregs);
|
||||
|
||||
enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sunxi_musb_disable(struct musb *musb)
|
||||
{
|
||||
pr_debug("%s():\n", __func__);
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
USBC_ForceVbusValidToLow(musb->mregs);
|
||||
mdelay(200); /* Wait for the current session to timeout */
|
||||
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
static int sunxi_musb_init(struct musb *musb)
|
||||
{
|
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
|
||||
pr_debug("%s():\n", __func__);
|
||||
|
||||
musb->isr = sunxi_musb_interrupt;
|
||||
|
||||
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
|
||||
#ifdef CONFIG_SUNXI_GEN_SUN6I
|
||||
setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
|
||||
#endif
|
||||
sunxi_usb_phy_init(0);
|
||||
|
||||
USBC_ConfigFIFO_Base();
|
||||
USBC_EnableDpDmPullUp(musb->mregs);
|
||||
USBC_EnableIdPullUp(musb->mregs);
|
||||
|
||||
if (is_host_enabled(musb)) {
|
||||
/* Host mode */
|
||||
USBC_ForceIdToLow(musb->mregs);
|
||||
} else {
|
||||
/* Peripheral mode */
|
||||
USBC_ForceIdToHigh(musb->mregs);
|
||||
}
|
||||
USBC_ForceVbusValidToHigh(musb->mregs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops sunxi_musb_ops = {
|
||||
.init = sunxi_musb_init,
|
||||
.enable = sunxi_musb_enable,
|
||||
.disable = sunxi_musb_disable,
|
||||
};
|
||||
|
||||
static struct musb_hdrc_config musb_config = {
|
||||
.multipoint = 1,
|
||||
.dyn_fifo = 1,
|
||||
.num_eps = 6,
|
||||
.ram_bits = 11,
|
||||
};
|
||||
|
||||
static struct musb_hdrc_platform_data musb_plat = {
|
||||
#if defined(CONFIG_USB_MUSB_HOST)
|
||||
.mode = MUSB_HOST,
|
||||
#else
|
||||
.mode = MUSB_PERIPHERAL,
|
||||
#endif
|
||||
.config = &musb_config,
|
||||
.power = 250,
|
||||
.platform_ops = &sunxi_musb_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_MUSB_HOST
|
||||
int musb_usb_probe(struct udevice *dev)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
|
||||
int ret;
|
||||
|
||||
priv->desc_before_addr = true;
|
||||
|
||||
if (!sunxi_musb) {
|
||||
sunxi_musb = musb_init_controller(&musb_plat, NULL,
|
||||
(void *)SUNXI_USB0_BASE);
|
||||
}
|
||||
|
||||
host->host = sunxi_musb;
|
||||
if (!host->host)
|
||||
return -EIO;
|
||||
|
||||
ret = musb_lowlevel_init(host);
|
||||
if (ret == 0)
|
||||
printf("MUSB OTG\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int musb_usb_remove(struct udevice *dev)
|
||||
{
|
||||
struct musb_host_data *host = dev_get_priv(dev);
|
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
|
||||
musb_stop(host->host);
|
||||
|
||||
sunxi_usb_phy_exit(0);
|
||||
#ifdef CONFIG_SUNXI_GEN_SUN6I
|
||||
clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
|
||||
#endif
|
||||
clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(usb_musb) = {
|
||||
.name = "sunxi-musb",
|
||||
.id = UCLASS_USB,
|
||||
.probe = musb_usb_probe,
|
||||
.remove = musb_usb_remove,
|
||||
.ops = &musb_usb_ops,
|
||||
.platdata_auto_alloc_size = sizeof(struct usb_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct musb_host_data),
|
||||
};
|
||||
#endif
|
||||
|
||||
void sunxi_musb_board_init(void)
|
||||
{
|
||||
#ifdef CONFIG_USB_MUSB_HOST
|
||||
struct udevice *dev;
|
||||
|
||||
/*
|
||||
* Bind the driver directly for now as musb linux kernel support is
|
||||
* still pending upstream so our dts files do not have the necessary
|
||||
* nodes yet. TODO: Remove this as soon as the dts nodes are in place
|
||||
* and bind by compatible instead.
|
||||
*/
|
||||
device_bind_driver(dm_root(), "sunxi-musb", "sunxi-musb", &dev);
|
||||
#else
|
||||
musb_register(&musb_plat, NULL, (void *)SUNXI_USB0_BASE);
|
||||
#endif
|
||||
}
|
||||
106
u-boot/drivers/usb/musb-new/usb-compat.h
Normal file
106
u-boot/drivers/usb/musb-new/usb-compat.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef __USB_COMPAT_H__
|
||||
#define __USB_COMPAT_H__
|
||||
|
||||
#include <dm.h>
|
||||
#include "usb.h"
|
||||
|
||||
struct usb_hcd {
|
||||
void *hcd_priv;
|
||||
};
|
||||
|
||||
struct usb_host_endpoint {
|
||||
struct usb_endpoint_descriptor desc;
|
||||
struct list_head urb_list;
|
||||
void *hcpriv;
|
||||
};
|
||||
|
||||
/*
|
||||
* urb->transfer_flags:
|
||||
*
|
||||
* Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
|
||||
*/
|
||||
#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */
|
||||
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */
|
||||
|
||||
struct urb;
|
||||
|
||||
typedef void (*usb_complete_t)(struct urb *);
|
||||
|
||||
struct urb {
|
||||
void *hcpriv; /* private data for host controller */
|
||||
struct list_head urb_list; /* list head for use by the urb's
|
||||
* current owner */
|
||||
struct usb_device *dev; /* (in) pointer to associated device */
|
||||
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
|
||||
unsigned int pipe; /* (in) pipe information */
|
||||
int status; /* (return) non-ISO status */
|
||||
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
|
||||
void *transfer_buffer; /* (in) associated data buffer */
|
||||
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
|
||||
u32 transfer_buffer_length; /* (in) data buffer length */
|
||||
u32 actual_length; /* (return) actual transfer length */
|
||||
unsigned char *setup_packet; /* (in) setup packet (control only) */
|
||||
int start_frame; /* (modify) start frame (ISO) */
|
||||
usb_complete_t complete; /* (in) completion routine */
|
||||
};
|
||||
|
||||
#define usb_hcd_link_urb_to_ep(hcd, urb) ({ \
|
||||
int ret = 0; \
|
||||
list_add_tail(&urb->urb_list, &urb->ep->urb_list); \
|
||||
ret; })
|
||||
#define usb_hcd_unlink_urb_from_ep(hcd, urb) list_del_init(&urb->urb_list)
|
||||
#define usb_hcd_check_unlink_urb(hdc, urb, status) 0
|
||||
|
||||
static inline void usb_hcd_giveback_urb(struct usb_hcd *hcd,
|
||||
struct urb *urb,
|
||||
int status)
|
||||
{
|
||||
urb->status = status;
|
||||
if (urb->complete)
|
||||
urb->complete(urb);
|
||||
}
|
||||
|
||||
static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd,
|
||||
struct urb *urb)
|
||||
{
|
||||
/* TODO: add cache invalidation here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
|
||||
{
|
||||
struct udevice *parent = udev->dev->parent;
|
||||
|
||||
/*
|
||||
* When called from usb-uclass.c: usb_scan_device() udev->dev points
|
||||
* to the parent udevice, not the actual udevice belonging to the
|
||||
* udev as the device is not instantiated yet.
|
||||
*
|
||||
* If dev is an usb-bus, then we are called from usb_scan_device() for
|
||||
* an usb-device plugged directly into the root port, return NULL.
|
||||
*/
|
||||
if (device_get_uclass_id(udev->dev) == UCLASS_USB)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If these 2 are not the same we are being called from
|
||||
* usb_scan_device() and udev itself is the parent.
|
||||
*/
|
||||
if (dev_get_parent_priv(udev->dev) != udev)
|
||||
return udev;
|
||||
|
||||
/* We are being called normally, use the parent pointer */
|
||||
if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
|
||||
return dev_get_parent_priv(parent);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static inline struct usb_device *usb_dev_get_parent(struct usb_device *dev)
|
||||
{
|
||||
return dev->parent;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USB_COMPAT_H__ */
|
||||
Reference in New Issue
Block a user