diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/musb/Kconfig | 29 | ||||
-rw-r--r-- | drivers/usb/musb/Makefile | 11 | ||||
-rw-r--r-- | drivers/usb/musb/musb_am335x.c | 48 | ||||
-rw-r--r-- | drivers/usb/musb/musb_barebox.c | 146 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 1323 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 85 | ||||
-rw-r--r-- | drivers/usb/musb/musb_dma.h | 1 | ||||
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 728 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 868 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.h | 10 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget_ep0.c | 18 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.c | 1065 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.h | 131 | ||||
-rw-r--r-- | drivers/usb/musb/musb_io.h | 2 | ||||
-rw-r--r-- | drivers/usb/musb/phy-am335x-control.c | 168 | ||||
-rw-r--r-- | drivers/usb/musb/phy-am335x.c | 86 | ||||
-rw-r--r-- | drivers/usb/musb/phy-am335x.h | 6 |
19 files changed, 898 insertions, 3831 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index eedd20e311..8520a2fd9b 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -19,3 +19,5 @@ endif source drivers/usb/gadget/Kconfig +source drivers/usb/musb/Kconfig + diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 44cb54a707..047f184800 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB_IMX_CHIPIDEA) += imx/ -obj-$(CONFIG_USB_MUSB_DSPS) += am335x/ +obj-$(CONFIG_USB_MUSB) += musb/ obj-$(CONFIG_USB_GADGET) += gadget/ obj-$(CONFIG_USB_STORAGE) += storage/ obj-y += host/ diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig new file mode 100644 index 0000000000..e0a1139bc0 --- /dev/null +++ b/drivers/usb/musb/Kconfig @@ -0,0 +1,29 @@ +config USB_MUSB + bool "MUSB support" + +if USB_MUSB + +config USB_MUSB_DSPS + tristate + +config USB_MUSB_AM335X + tristate "AM335x USB support" + depends on ARCH_AM33XX + select USB_MUSB_DSPS + help + This driver provides the necessary bit to enable USB support + on the TI AM335x SoC. + +config USB_MUSB_HOST + bool "MUSB Host mode support" + depends on USB_HOST + help + Select this when you want to use MUSB in host mode. + +config USB_MUSB_GADGET + bool "MUSB Gadget mode support" + depends on USB_GADGET + help + Select this when you want to use MUSB in gadget mode. + +endif diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile new file mode 100644 index 0000000000..364a43fecb --- /dev/null +++ b/drivers/usb/musb/Makefile @@ -0,0 +1,11 @@ +# +# for USB OTG silicon based on Mentor Graphics INVENTRA designs +# + +obj-y += musb_core.o musb_barebox.o + +obj-$(CONFIG_USB_MUSB_HOST) += musb_host.o +obj-$(CONFIG_USB_MUSB_GADGET) += musb_gadget.o musb_gadget_ep0.o + +obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o +obj-$(CONFIG_USB_MUSB_AM335X) += phy-am335x-control.o musb_am335x.o phy-am335x.o diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c index 1e58ed2361..2a9167a245 100644 --- a/drivers/usb/musb/musb_am335x.c +++ b/drivers/usb/musb/musb_am335x.c @@ -1,43 +1,29 @@ -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/module.h> -#include <linux/of_platform.h> +#include <common.h> +#include <init.h> +#include <linux/clk.h> -static int am335x_child_probe(struct platform_device *pdev) +static int am335x_child_probe(struct device_d *dev) { int ret; - pm_runtime_enable(&pdev->dev); - - ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + ret = of_platform_populate(dev->device_node, NULL, dev); if (ret) - goto err; + return ret; return 0; -err: - pm_runtime_disable(&pdev->dev); - return ret; } -static const struct of_device_id am335x_child_of_match[] = { - { .compatible = "ti,am33xx-usb" }, - { }, -}; -MODULE_DEVICE_TABLE(of, am335x_child_of_match); - -static struct platform_driver am335x_child_driver = { - .probe = am335x_child_probe, - .driver = { - .name = "am335x-usb-childs", - .of_match_table = am335x_child_of_match, +static __maybe_unused struct of_device_id am335x_child_dt_ids[] = { + { + .compatible = "ti,am33xx-usb", + }, { + /* sentinel */ }, }; -static int __init am335x_child_init(void) -{ - return platform_driver_register(&am335x_child_driver); -} -module_init(am335x_child_init); - -MODULE_DESCRIPTION("AM33xx child devices"); -MODULE_LICENSE("GPL v2"); +static struct driver_d am335x_child_driver = { + .name = "am335x_child_probe", + .probe = am335x_child_probe, + .of_compatible = DRV_OF_COMPAT(am335x_child_dt_ids), +}; +device_platform_driver(am335x_child_driver); diff --git a/drivers/usb/musb/musb_barebox.c b/drivers/usb/musb/musb_barebox.c new file mode 100644 index 0000000000..6bc232b570 --- /dev/null +++ b/drivers/usb/musb/musb_barebox.c @@ -0,0 +1,146 @@ +#include <common.h> +#include <init.h> +#include <clock.h> +#include <usb/musb.h> +#include <usb/usb.h> +#include <linux/types.h> +#include <linux/err.h> +#include <linux/barebox-wrapper.h> + +#include "musb_core.h" +#include "musb_gadget.h" + +static struct usb_host_endpoint hep; +static struct urb urb; + +static void musb_host_complete_urb(struct urb *urb) +{ + urb->dev->status &= ~USB_ST_NOT_PROC; + urb->dev->act_len = urb->actual_length; +} + +static struct urb *construct_urb(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; + + return &urb; +} + +#define MUSB_HOST_TIMEOUT 0x5fffff + +static int submit_urb(struct usb_device *dev, struct urb *urb, int timeout_ms) +{ + struct usb_host *host = dev->host; + struct musb *musb = to_musb(host); + int ret; + uint64_t start; + uint64_t timeout = timeout_ms; + + ret = musb_urb_enqueue(musb->hcd, urb, 0); + if (ret < 0) { + printf("Failed to enqueue URB to controller\n"); + return ret; + } + + start = get_time_ns(); + + do { + musb->isr(musb); + + if (!urb->status) + return 0; + + } while (!is_timeout(start, timeout * MSECOND)); + + if (urb->dev->status & USB_ST_NOT_PROC) + ret = -ETIMEDOUT; + else + ret = urb->status; + + musb_urb_dequeue(musb->hcd, urb, -ECONNRESET); + + return ret; +} + +static int +submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, int timeout) +{ + struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_BULK, pipe, + buffer, length, NULL, 0); + return submit_urb(dev, urb, timeout); +} + +static int +submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, struct devrequest *setup, int timeout) +{ + struct usb_host *host = dev->host; + struct musb *musb = to_musb(host); + struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_CONTROL, pipe, + buffer, length, setup, 0); + + /* Fix speed for non hub-attached devices */ + if (!dev->parent) + dev->speed = musb->host_speed; + + return submit_urb(dev, urb, timeout); +} + +static int +submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, int interval) +{ + struct urb *urb = construct_urb(dev, USB_ENDPOINT_XFER_INT, pipe, + buffer, length, NULL, interval); + return submit_urb(dev, urb, 100); +} + +static int musb_detect(struct device_d *dev) +{ + struct musb *musb = dev->priv; + + return usb_host_detect(&musb->host); +} + +int musb_register(struct musb *musb) +{ + struct usb_host *host; + + host = &musb->host; + host->hw_dev = musb->controller; + host->init = musb_init; + host->submit_int_msg = submit_int_msg; + host->submit_control_msg = submit_control_msg; + host->submit_bulk_msg = submit_bulk_msg; + + musb->controller->detect = musb_detect; + usb_register_host(host); + + return 0; +} diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b841ee0bff..ccb702980f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -89,18 +89,17 @@ * Most of the conditional compilation will (someday) vanish. */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/kobject.h> -#include <linux/prefetch.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/dma-mapping.h> +#include <common.h> +#include <init.h> +#include <clock.h> +#include <usb/musb.h> +#include <usb/usb.h> +#include <linux/types.h> +#include <linux/err.h> +#include <linux/barebox-wrapper.h> #include "musb_core.h" +#include "musb_gadget.h" #define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) @@ -120,13 +119,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" MUSB_DRIVER_NAME); - -/*-------------------------------------------------------------------------*/ - -static inline struct musb *dev_to_musb(struct device *dev) -{ - return dev_get_drvdata(dev); -} +#define MUSB_HOST_TIMEOUT 0x5fffff /*-------------------------------------------------------------------------*/ @@ -139,8 +132,6 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset) u8 power; int ret; - pm_runtime_get_sync(phy->io_dev); - /* Make sure the transceiver is not in low power mode */ power = musb_readb(addr, MUSB_POWER); power &= ~MUSB_POWER_SUSPENDM; @@ -170,8 +161,6 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset) ret = musb_readb(addr, MUSB_ULPI_REG_DATA); out: - pm_runtime_put(phy->io_dev); - return ret; } @@ -183,8 +172,6 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) u8 power; int ret = 0; - pm_runtime_get_sync(phy->io_dev); - /* Make sure the transceiver is not in low power mode */ power = musb_readb(addr, MUSB_POWER); power &= ~MUSB_POWER_SUSPENDM; @@ -208,8 +195,6 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); out: - pm_runtime_put(phy->io_dev); - return ret; } #else @@ -217,7 +202,7 @@ out: #define musb_ulpi_write NULL #endif -static struct usb_phy_io_ops musb_ulpi_access = { +struct usb_phy_io_ops musb_ulpi_access = { .read = musb_ulpi_read, .write = musb_ulpi_write, }; @@ -249,7 +234,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) /* best case is 32bit-aligned source address */ if ((0x02 & (unsigned long) src) == 0) { if (len >= 4) { - iowrite32_rep(fifo, src + index, len >> 2); + writesl(fifo, src + index, len >> 2); index += len & ~0x03; } if (len & 0x02) { @@ -258,7 +243,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) } } else { if (len >= 2) { - iowrite16_rep(fifo, src + index, len >> 1); + writesw(fifo, src + index, len >> 1); index += len & ~0x01; } } @@ -266,7 +251,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) musb_writeb(fifo, 0, src[index]); } else { /* byte aligned */ - iowrite8_rep(fifo, src, len); + writesb(fifo, src, len); } } @@ -292,7 +277,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) /* best case is 32bit-aligned destination address */ if ((0x02 & (unsigned long) dst) == 0) { if (len >= 4) { - ioread32_rep(fifo, dst, len >> 2); + readsl(fifo, dst, len >> 2); index = len & ~0x03; } if (len & 0x02) { @@ -301,7 +286,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) } } else { if (len >= 2) { - ioread16_rep(fifo, dst, len >> 1); + readsw(fifo, dst, len >> 1); index = len & ~0x01; } } @@ -309,16 +294,16 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) dst[index] = musb_readb(fifo, 0); } else { /* byte aligned */ - ioread8_rep(fifo, dst, len); + readsb(fifo, dst, len); } } #endif #endif /* normal PIO */ - /*-------------------------------------------------------------------------*/ + /* for high speed test mode; see USB 2.0 spec 7.1.20 */ static const u8 musb_test_packet[53] = { /* implicit SYNC then DATA0 to start */ @@ -351,560 +336,6 @@ void musb_load_testpacket(struct musb *musb) /*-------------------------------------------------------------------------*/ -/* - * Handles OTG hnp timeouts, such as b_ase0_brst - */ -static void musb_otg_timer_func(unsigned long data) -{ - struct musb *musb = (struct musb *)data; - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { - case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n"); - musb_g_disconnect(musb); - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - musb->is_active = 0; - break; - case OTG_STATE_A_SUSPEND: - case OTG_STATE_A_WAIT_BCON: - dev_dbg(musb->controller, "HNP: %s timeout\n", - usb_otg_state_string(musb->xceiv->state)); - musb_platform_set_vbus(musb, 0); - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; - break; - default: - dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", - usb_otg_state_string(musb->xceiv->state)); - } - spin_unlock_irqrestore(&musb->lock, flags); -} - -/* - * Stops the HNP transition. Caller must take care of locking. - */ -void musb_hnp_stop(struct musb *musb) -{ - struct usb_hcd *hcd = musb->hcd; - void __iomem *mbase = musb->mregs; - u8 reg; - - dev_dbg(musb->controller, "HNP: stop from %s\n", - usb_otg_state_string(musb->xceiv->state)); - - switch (musb->xceiv->state) { - case OTG_STATE_A_PERIPHERAL: - musb_g_disconnect(musb); - dev_dbg(musb->controller, "HNP: back to %s\n", - usb_otg_state_string(musb->xceiv->state)); - break; - case OTG_STATE_B_HOST: - dev_dbg(musb->controller, "HNP: Disabling HR\n"); - if (hcd) - hcd->self.is_b_host = 0; - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - MUSB_DEV_MODE(musb); - reg = musb_readb(mbase, MUSB_POWER); - reg |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, reg); - /* REVISIT: Start SESSION_REQUEST here? */ - break; - default: - dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", - usb_otg_state_string(musb->xceiv->state)); - } - - /* - * When returning to A state after HNP, avoid hub_port_rebounce(), - * which cause occasional OPT A "Did not receive reset after connect" - * errors. - */ - musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16); -} - -/* - * Interrupt Service Routine to record USB "global" interrupts. - * Since these do not happen often and signify things of - * paramount importance, it seems OK to check them individually; - * the order of the tests is specified in the manual - * - * @param musb instance pointer - * @param int_usb register contents - * @param devctl - * @param power - */ - -static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, - u8 devctl) -{ - irqreturn_t handled = IRQ_NONE; - - dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl, - int_usb); - - /* in host mode, the peripheral may issue remote wakeup. - * in peripheral mode, the host may resume the link. - * spurious RESUME irqs happen too, paired with SUSPEND. - */ - if (int_usb & MUSB_INTR_RESUME) { - handled = IRQ_HANDLED; - dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state)); - - if (devctl & MUSB_DEVCTL_HM) { - void __iomem *mbase = musb->mregs; - u8 power; - - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - /* remote wakeup? later, GetPortStatus - * will stop RESUME signaling - */ - - power = musb_readb(musb->mregs, MUSB_POWER); - if (power & MUSB_POWER_SUSPENDM) { - /* spurious */ - musb->int_usb &= ~MUSB_INTR_SUSPEND; - dev_dbg(musb->controller, "Spurious SUSPENDM\n"); - break; - } - - power &= ~MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, - power | MUSB_POWER_RESUME); - - musb->port1_status |= - (USB_PORT_STAT_C_SUSPEND << 16) - | MUSB_PORT_STAT_RESUME; - musb->rh_timer = jiffies - + msecs_to_jiffies(20); - schedule_delayed_work( - &musb->finish_resume_work, - msecs_to_jiffies(20)); - - musb->xceiv->state = OTG_STATE_A_HOST; - musb->is_active = 1; - musb_host_resume_root_hub(musb); - break; - case OTG_STATE_B_WAIT_ACON: - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - musb->is_active = 1; - MUSB_DEV_MODE(musb); - break; - default: - WARNING("bogus %s RESUME (%s)\n", - "host", - usb_otg_state_string(musb->xceiv->state)); - } - } else { - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - /* possibly DISCONNECT is upcoming */ - musb->xceiv->state = OTG_STATE_A_HOST; - musb_host_resume_root_hub(musb); - break; - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_PERIPHERAL: - /* disconnect while suspended? we may - * not get a disconnect irq... - */ - if ((devctl & MUSB_DEVCTL_VBUS) - != (3 << MUSB_DEVCTL_VBUS_SHIFT) - ) { - musb->int_usb |= MUSB_INTR_DISCONNECT; - musb->int_usb &= ~MUSB_INTR_SUSPEND; - break; - } - musb_g_resume(musb); - break; - case OTG_STATE_B_IDLE: - musb->int_usb &= ~MUSB_INTR_SUSPEND; - break; - default: - WARNING("bogus %s RESUME (%s)\n", - "peripheral", - usb_otg_state_string(musb->xceiv->state)); - } - } - } - - /* see manual for the order of the tests */ - if (int_usb & MUSB_INTR_SESSREQ) { - void __iomem *mbase = musb->mregs; - - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS - && (devctl & MUSB_DEVCTL_BDEVICE)) { - dev_dbg(musb->controller, "SessReq while on B state\n"); - return IRQ_HANDLED; - } - - dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", - usb_otg_state_string(musb->xceiv->state)); - - /* IRQ arrives from ID pin sense or (later, if VBUS power - * is removed) SRP. responses are time critical: - * - turn on VBUS (with silicon-specific mechanism) - * - go through A_WAIT_VRISE - * - ... to A_WAIT_BCON. - * a_wait_vrise_tmout triggers VBUS_ERROR transitions - */ - musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - musb->ep0_stage = MUSB_EP0_START; - musb->xceiv->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - musb_platform_set_vbus(musb, 1); - - handled = IRQ_HANDLED; - } - - if (int_usb & MUSB_INTR_VBUSERROR) { - int ignore = 0; - - /* During connection as an A-Device, we may see a short - * current spikes causing voltage drop, because of cable - * and peripheral capacitance combined with vbus draw. - * (So: less common with truly self-powered devices, where - * vbus doesn't act like a power supply.) - * - * Such spikes are short; usually less than ~500 usec, max - * of ~2 msec. That is, they're not sustained overcurrent - * errors, though they're reported using VBUSERROR irqs. - * - * Workarounds: (a) hardware: use self powered devices. - * (b) software: ignore non-repeated VBUS errors. - * - * REVISIT: do delays from lots of DEBUG_KERNEL checks - * make trouble here, keeping VBUS < 4.4V ? - */ - switch (musb->xceiv->state) { - case OTG_STATE_A_HOST: - /* recovery is dicey once we've gotten past the - * initial stages of enumeration, but if VBUS - * stayed ok at the other end of the link, and - * another reset is due (at least for high speed, - * to redo the chirp etc), it might work OK... - */ - case OTG_STATE_A_WAIT_BCON: - case OTG_STATE_A_WAIT_VRISE: - if (musb->vbuserr_retry) { - void __iomem *mbase = musb->mregs; - - musb->vbuserr_retry--; - ignore = 1; - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(mbase, MUSB_DEVCTL, devctl); - } else { - musb->port1_status |= - USB_PORT_STAT_OVERCURRENT - | (USB_PORT_STAT_C_OVERCURRENT << 16); - } - break; - default: - break; - } - - dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller, - "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", - usb_otg_state_string(musb->xceiv->state), - devctl, - ({ char *s; - switch (devctl & MUSB_DEVCTL_VBUS) { - case 0 << MUSB_DEVCTL_VBUS_SHIFT: - s = "<SessEnd"; break; - case 1 << MUSB_DEVCTL_VBUS_SHIFT: - s = "<AValid"; break; - case 2 << MUSB_DEVCTL_VBUS_SHIFT: - s = "<VBusValid"; break; - /* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */ - default: - s = "VALID"; break; - } s; }), - VBUSERR_RETRY_COUNT - musb->vbuserr_retry, - musb->port1_status); - - /* go through A_WAIT_VFALL then start a new session */ - if (!ignore) - musb_platform_set_vbus(musb, 0); - handled = IRQ_HANDLED; - } - - if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", - usb_otg_state_string(musb->xceiv->state), devctl); - handled = IRQ_HANDLED; - - switch (musb->xceiv->state) { - case OTG_STATE_A_PERIPHERAL: - /* We also come here if the cable is removed, since - * this silicon doesn't report ID-no-longer-grounded. - * - * We depend on T(a_wait_bcon) to shut us down, and - * hope users don't do anything dicey during this - * undesired detour through A_WAIT_BCON. - */ - musb_hnp_stop(musb); - musb_host_resume_root_hub(musb); - musb_root_disconnect(musb); - musb_platform_try_idle(musb, jiffies - + msecs_to_jiffies(musb->a_wait_bcon - ? : OTG_TIME_A_WAIT_BCON)); - - break; - case OTG_STATE_B_IDLE: - if (!musb->is_active) - break; - case OTG_STATE_B_PERIPHERAL: - musb_g_suspend(musb); - musb->is_active = musb->g.b_hnp_enable; - if (musb->is_active) { - musb->xceiv->state = OTG_STATE_B_WAIT_ACON; - dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); - mod_timer(&musb->otg_timer, jiffies - + msecs_to_jiffies( - OTG_TIME_B_ASE0_BRST)); - } - break; - case OTG_STATE_A_WAIT_BCON: - if (musb->a_wait_bcon != 0) - musb_platform_try_idle(musb, jiffies - + msecs_to_jiffies(musb->a_wait_bcon)); - break; - case OTG_STATE_A_HOST: - musb->xceiv->state = OTG_STATE_A_SUSPEND; - musb->is_active = musb->hcd->self.b_hnp_enable; - break; - case OTG_STATE_B_HOST: - /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ - dev_dbg(musb->controller, "REVISIT: SUSPEND as B_HOST\n"); - break; - default: - /* "should not happen" */ - musb->is_active = 0; - break; - } - } - - if (int_usb & MUSB_INTR_CONNECT) { - struct usb_hcd *hcd = musb->hcd; - - handled = IRQ_HANDLED; - musb->is_active = 1; - - musb->ep0_stage = MUSB_EP0_START; - - /* flush endpoints when transitioning from Device Mode */ - if (is_peripheral_active(musb)) { - /* REVISIT HNP; just force disconnect */ - } - musb->intrtxe = musb->epmask; - musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe); - musb->intrrxe = musb->epmask & 0xfffe; - musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe); - musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7); - musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED - |USB_PORT_STAT_HIGH_SPEED - |USB_PORT_STAT_ENABLE - ); - musb->port1_status |= USB_PORT_STAT_CONNECTION - |(USB_PORT_STAT_C_CONNECTION << 16); - - /* high vs full speed is just a guess until after reset */ - if (devctl & MUSB_DEVCTL_LSDEV) - musb->port1_status |= USB_PORT_STAT_LOW_SPEED; - - /* indicate new connection to OTG machine */ - switch (musb->xceiv->state) { - case OTG_STATE_B_PERIPHERAL: - if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n"); - int_usb &= ~MUSB_INTR_SUSPEND; - goto b_host; - } else - dev_dbg(musb->controller, "CONNECT as b_peripheral???\n"); - break; - case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n"); -b_host: - musb->xceiv->state = OTG_STATE_B_HOST; - if (musb->hcd) - musb->hcd->self.is_b_host = 1; - del_timer(&musb->otg_timer); - break; - default: - if ((devctl & MUSB_DEVCTL_VBUS) - == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { - musb->xceiv->state = OTG_STATE_A_HOST; - if (hcd) - hcd->self.is_b_host = 0; - } - break; - } - - musb_host_poke_root_hub(musb); - - dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", - usb_otg_state_string(musb->xceiv->state), devctl); - } - - if (int_usb & MUSB_INTR_DISCONNECT) { - dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", - usb_otg_state_string(musb->xceiv->state), - MUSB_MODE(musb), devctl); - handled = IRQ_HANDLED; - - switch (musb->xceiv->state) { - case OTG_STATE_A_HOST: - case OTG_STATE_A_SUSPEND: - musb_host_resume_root_hub(musb); - musb_root_disconnect(musb); - if (musb->a_wait_bcon != 0) - musb_platform_try_idle(musb, jiffies - + msecs_to_jiffies(musb->a_wait_bcon)); - break; - case OTG_STATE_B_HOST: - /* REVISIT this behaves for "real disconnect" - * cases; make sure the other transitions from - * from B_HOST act right too. The B_HOST code - * in hnp_stop() is currently not used... - */ - musb_root_disconnect(musb); - if (musb->hcd) - musb->hcd->self.is_b_host = 0; - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - MUSB_DEV_MODE(musb); - musb_g_disconnect(musb); - break; - case OTG_STATE_A_PERIPHERAL: - musb_hnp_stop(musb); - musb_root_disconnect(musb); - /* FALLTHROUGH */ - case OTG_STATE_B_WAIT_ACON: - /* FALLTHROUGH */ - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_IDLE: - musb_g_disconnect(musb); - break; - default: - WARNING("unhandled DISCONNECT transition (%s)\n", - usb_otg_state_string(musb->xceiv->state)); - break; - } - } - - /* mentor saves a bit: bus reset and babble share the same irq. - * only host sees babble; only peripheral sees bus reset. - */ - if (int_usb & MUSB_INTR_RESET) { - handled = IRQ_HANDLED; - if ((devctl & MUSB_DEVCTL_HM) != 0) { - /* - * Looks like non-HS BABBLE can be ignored, but - * HS BABBLE is an error condition. For HS the solution - * is to avoid babble in the first place and fix what - * caused BABBLE. When HS BABBLE happens we can only - * stop the session. - */ - if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV)) - dev_dbg(musb->controller, "BABBLE devctl: %02x\n", devctl); - else { - ERR("Stopping host session -- babble\n"); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - } - } else { - dev_dbg(musb->controller, "BUS RESET as %s\n", - usb_otg_state_string(musb->xceiv->state)); - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - musb_g_reset(musb); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ - /* never use invalid T(a_wait_bcon) */ - dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", - usb_otg_state_string(musb->xceiv->state), - TA_WAIT_BCON(musb)); - mod_timer(&musb->otg_timer, jiffies - + msecs_to_jiffies(TA_WAIT_BCON(musb))); - break; - case OTG_STATE_A_PERIPHERAL: - del_timer(&musb->otg_timer); - musb_g_reset(musb); - break; - case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", - usb_otg_state_string(musb->xceiv->state)); - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - musb_g_reset(musb); - break; - case OTG_STATE_B_IDLE: - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - /* FALLTHROUGH */ - case OTG_STATE_B_PERIPHERAL: - musb_g_reset(musb); - break; - default: - dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", - usb_otg_state_string(musb->xceiv->state)); - } - } - } - - /* handle babble condition */ - if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) - schedule_delayed_work(&musb->recover_work, - msecs_to_jiffies(100)); - -#if 0 -/* REVISIT ... this would be for multiplexing periodic endpoints, or - * supporting transfer phasing to prevent exceeding ISO bandwidth - * limits of a given frame or microframe. - * - * It's not needed for peripheral side, which dedicates endpoints; - * though it _might_ use SOF irqs for other purposes. - * - * And it's not currently needed for host side, which also dedicates - * endpoints, relies on TX/RX interval registers, and isn't claimed - * to support ISO transfers yet. - */ - if (int_usb & MUSB_INTR_SOF) { - void __iomem *mbase = musb->mregs; - struct musb_hw_ep *ep; - u8 epnum; - u16 frame; - - dev_dbg(musb->controller, "START_OF_FRAME\n"); - handled = IRQ_HANDLED; - - /* start any periodic Tx transfers waiting for current frame */ - frame = musb_readw(mbase, MUSB_FRAME); - ep = musb->endpoints; - for (epnum = 1; (epnum < musb->nr_endpoints) - && (musb->epmask >= (1 << epnum)); - epnum++, ep++) { - /* - * FIXME handle framecounter wraps (12 bits) - * eliminate duplicated StartUrb logic - */ - if (ep->dwWaitFrame >= frame) { - ep->dwWaitFrame = 0; - pr_debug("SOF --> periodic TX%s on %d\n", - ep->tx_channel ? " DMA" : "", - epnum); - if (!ep->tx_channel) - musb_h_tx_start(musb, epnum); - else - cppi_hostdma_start(musb, epnum); - } - } /* end of for loop */ - } -#endif - - schedule_work(&musb->irq_work); - - return handled; -} - -/*-------------------------------------------------------------------------*/ - static void musb_generic_disable(struct musb *musb) { void __iomem *mbase = musb->mregs; @@ -997,29 +428,6 @@ void musb_stop(struct musb *musb) musb_platform_try_idle(musb, 0); } -static void musb_shutdown(struct platform_device *pdev) -{ - struct musb *musb = dev_to_musb(&pdev->dev); - unsigned long flags; - - pm_runtime_get_sync(musb->controller); - - musb_host_cleanup(musb); - musb_gadget_cleanup(musb); - - spin_lock_irqsave(&musb->lock, flags); - musb_platform_disable(musb); - musb_generic_disable(musb); - spin_unlock_irqrestore(&musb->lock, flags); - - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_platform_exit(musb); - - pm_runtime_put(musb->controller); - /* FIXME power down */ -} - - /*-------------------------------------------------------------------------*/ /* @@ -1048,10 +456,6 @@ static ushort fifo_mode = 5; static ushort fifo_mode = 2; #endif -/* "modprobe ... fifo_mode=1" etc */ -module_param(fifo_mode, ushort, 0); -MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration"); - /* * tables defining fifo_mode values. define more if you like. * for host side, make sure both halves of ep1 are set up. @@ -1521,13 +925,6 @@ irqreturn_t musb_interrupt(struct musb *musb) is_host_active(musb) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); - /* the core can interrupt us for multiple reasons; docs have - * a generic interrupt flowchart to follow - */ - if (musb->int_usb) - retval |= musb_stage0_irq(musb, musb->int_usb, - devctl); - /* "stage 1" is handling endpoint irqs */ /* handle endpoint 0 first */ @@ -1577,232 +974,23 @@ irqreturn_t musb_interrupt(struct musb *musb) } EXPORT_SYMBOL_GPL(musb_interrupt); -#ifndef CONFIG_MUSB_PIO_ONLY -static bool use_dma = 1; - -/* "modprobe ... use_dma=0" etc */ -module_param(use_dma, bool, 0); -MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); - -void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) -{ - /* called with controller lock already held */ - - if (!epnum) { -#ifndef CONFIG_USB_TUSB_OMAP_DMA - if (!is_cppi_enabled()) { - /* endpoint 0 */ - if (is_host_active(musb)) - musb_h_ep0_irq(musb); - else - musb_g_ep0_irq(musb); - } -#endif - } else { - /* endpoints 1..15 */ - if (transmit) { - if (is_host_active(musb)) - musb_host_tx(musb, epnum); - else - musb_g_tx(musb, epnum); - } else { - /* receive */ - if (is_host_active(musb)) - musb_host_rx(musb, epnum); - else - musb_g_rx(musb, epnum); - } - } -} -EXPORT_SYMBOL_GPL(musb_dma_completion); - -#else -#define use_dma 0 -#endif - -/*-------------------------------------------------------------------------*/ - -static ssize_t -musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&musb->lock, flags); - ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state)); - spin_unlock_irqrestore(&musb->lock, flags); - - return ret; -} - -static ssize_t -musb_mode_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - int status; - - spin_lock_irqsave(&musb->lock, flags); - if (sysfs_streq(buf, "host")) - status = musb_platform_set_mode(musb, MUSB_HOST); - else if (sysfs_streq(buf, "peripheral")) - status = musb_platform_set_mode(musb, MUSB_PERIPHERAL); - else if (sysfs_streq(buf, "otg")) - status = musb_platform_set_mode(musb, MUSB_OTG); - else - status = -EINVAL; - spin_unlock_irqrestore(&musb->lock, flags); - - return (status == 0) ? n : status; -} -static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store); - -static ssize_t -musb_vbus_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - unsigned long val; - - if (sscanf(buf, "%lu", &val) < 1) { - dev_err(dev, "Invalid VBUS timeout ms value\n"); - return -EINVAL; - } - - spin_lock_irqsave(&musb->lock, flags); - /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */ - musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ; - if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON) - musb->is_active = 0; - musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val)); - spin_unlock_irqrestore(&musb->lock, flags); - - return n; -} - -static ssize_t -musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - unsigned long val; - int vbus; - - spin_lock_irqsave(&musb->lock, flags); - val = musb->a_wait_bcon; - /* FIXME get_vbus_status() is normally #defined as false... - * and is effectively TUSB-specific. - */ - vbus = musb_platform_get_vbus_status(musb); - spin_unlock_irqrestore(&musb->lock, flags); - - return sprintf(buf, "Vbus %s, timeout %lu msec\n", - vbus ? "on" : "off", val); -} -static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); - -/* Gadget drivers can't know that a host is connected so they might want - * to start SRP, but users can. This allows userspace to trigger SRP. - */ -static ssize_t -musb_srp_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned short srp; - - if (sscanf(buf, "%hu", &srp) != 1 - || (srp != 1)) { - dev_err(dev, "SRP: Value must be 1\n"); - return -EINVAL; - } - - if (srp == 1) - musb_g_wakeup(musb); - - return n; -} -static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); - -static struct attribute *musb_attributes[] = { - &dev_attr_mode.attr, - &dev_attr_vbus.attr, - &dev_attr_srp.attr, - NULL -}; - -static const struct attribute_group musb_attr_group = { - .attrs = musb_attributes, -}; - -/* Only used to provide driver mode change events */ -static void musb_irq_work(struct work_struct *data) -{ - struct musb *musb = container_of(data, struct musb, irq_work); - - if (musb->xceiv->state != musb->xceiv_old_state) { - musb->xceiv_old_state = musb->xceiv->state; - sysfs_notify(&musb->controller->kobj, NULL, "mode"); - } -} - -/* Recover from babble interrupt conditions */ -static void musb_recover_work(struct work_struct *data) -{ - struct musb *musb = container_of(data, struct musb, recover_work.work); - int status, ret; - - ret = musb_platform_reset(musb); - if (ret) - return; - - usb_phy_vbus_off(musb->xceiv); - usleep_range(100, 200); - - usb_phy_vbus_on(musb->xceiv); - usleep_range(100, 200); - - /* - * When a babble condition occurs, the musb controller - * removes the session bit and the endpoint config is lost. - */ - if (musb->dyn_fifo) - status = ep_config_from_table(musb); - else - status = ep_config_from_hw(musb); - - /* start the session again */ - if (status == 0) - musb_start(musb); -} - /* -------------------------------------------------------------------------- * Init support */ -static struct musb *allocate_instance(struct device *dev, - struct musb_hdrc_config *config, void __iomem *mbase) +static struct musb *musb_init_instance(struct musb *musb, + struct musb_hdrc_config *config) { - struct musb *musb; struct musb_hw_ep *ep; int epnum; int ret; - musb = devm_kzalloc(dev, sizeof(*musb), GFP_KERNEL); - if (!musb) - return NULL; - INIT_LIST_HEAD(&musb->control); INIT_LIST_HEAD(&musb->in_bulk); INIT_LIST_HEAD(&musb->out_bulk); musb->vbuserr_retry = VBUSERR_RETRY_COUNT; musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON; - musb->mregs = mbase; - musb->ctrl_base = mbase; musb->nIrq = -ENODEV; musb->config = config; BUG_ON(musb->config->num_eps > MUSB_C_NUM_EPS); @@ -1813,14 +1001,10 @@ static struct musb *allocate_instance(struct device *dev, ep->epnum = epnum; } - musb->controller = dev; - ret = musb_host_alloc(musb); if (ret < 0) goto err_free; - dev_set_drvdata(dev, musb); - return musb; err_free: @@ -1834,32 +1018,40 @@ static void musb_free(struct musb *musb) * cleanup after everything's been de-activated. */ -#ifdef CONFIG_SYSFS - sysfs_remove_group(&musb->controller->kobj, &musb_attr_group); -#endif - - if (musb->nIrq >= 0) { - if (musb->irq_wake) - disable_irq_wake(musb->nIrq); - free_irq(musb->nIrq, musb); - } - musb_host_free(musb); } -static void musb_deassert_reset(struct work_struct *work) +int musb_init(struct usb_host *host) { - struct musb *musb; - unsigned long flags; + struct musb *musb = to_musb(host); + void *mbase; + int timeout = MUSB_HOST_TIMEOUT; + u8 power; - musb = container_of(work, struct musb, deassert_reset_work.work); + musb_start(musb); + mbase = musb->mregs; + do { + if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM) + break; + } while (--timeout); + if (!timeout) + return -ENODEV; - spin_lock_irqsave(&musb->lock, flags); + power = musb_readb(mbase, MUSB_POWER); + musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); + udelay(30000); + power = musb_readb(mbase, MUSB_POWER); + musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power); - if (musb->port1_status & USB_PORT_STAT_RESET) - musb_port_reset(musb, false); + musb->isr(musb); + udelay(30000); /* necessary for proper hub detection */ + musb->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; + musb->is_active = 1; - spin_unlock_irqrestore(&musb->lock, flags); + return 0; } /* @@ -1870,34 +1062,18 @@ static void musb_deassert_reset(struct work_struct *work) * @ctrl: virtual address of controller registers, * not yet corrected for platform-specific offsets */ -static int -musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) +int +musb_init_controller(struct musb *musb, struct musb_hdrc_platform_data *plat) { int status; - struct musb *musb; - struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); - - /* The driver might handle more features than the board; OK. - * Fail when the board needs a feature that's not enabled. - */ - if (!plat) { - dev_dbg(dev, "no platform_data?\n"); - status = -ENODEV; - goto fail0; - } /* allocate */ - musb = allocate_instance(dev, plat->config, ctrl); + musb = musb_init_instance(musb, plat->config); if (!musb) { status = -ENOMEM; goto fail0; } - pm_runtime_use_autosuspend(musb->controller); - pm_runtime_set_autosuspend_delay(musb->controller, 200); - pm_runtime_enable(musb->controller); - - spin_lock_init(&musb->lock); musb->board_set_power = plat->set_power; musb->min_power = plat->min_power; musb->ops = plat->platform_ops; @@ -1924,32 +1100,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) goto fail2; } - if (!musb->xceiv->io_ops) { - musb->xceiv->io_dev = musb->controller; - musb->xceiv->io_priv = musb->mregs; - musb->xceiv->io_ops = &musb_ulpi_access; - } - - pm_runtime_get_sync(musb->controller); - - if (use_dma && dev->dma_mask) { - musb->dma_controller = dma_controller_create(musb, musb->mregs); - if (IS_ERR(musb->dma_controller)) { - status = PTR_ERR(musb->dma_controller); - goto fail2_5; - } - } - /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); musb_generic_disable(musb); - /* Init IRQ workqueue before request_irq */ - INIT_WORK(&musb->irq_work, musb_irq_work); - INIT_DELAYED_WORK(&musb->recover_work, musb_recover_work); - INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); - INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); - /* setup musb parts of the core (especially endpoints) */ status = musb_core_init(plat->config->multipoint ? MUSB_CONTROLLER_MHDRC @@ -1957,106 +1111,39 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (status < 0) goto fail3; - setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); - - /* attach to the IRQ */ - if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { - dev_err(dev, "request_irq %d failed!\n", nIrq); - status = -ENODEV; - goto fail3; - } - musb->nIrq = nIrq; - /* FIXME this handles wakeup irqs wrong */ - if (enable_irq_wake(nIrq) == 0) { - musb->irq_wake = 1; - device_init_wakeup(dev, 1); - } else { - musb->irq_wake = 0; - } - - /* program PHY to use external vBus if required */ - if (plat->extvbus) { - u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); - busctl |= MUSB_ULPI_USE_EXTVBUS; - musb_write_ulpi_buscontrol(musb->mregs, busctl); - } - - if (musb->xceiv->otg->default_a) { - MUSB_HST_MODE(musb); - musb->xceiv->state = OTG_STATE_A_IDLE; - } else { - MUSB_DEV_MODE(musb); - musb->xceiv->state = OTG_STATE_B_IDLE; - } - switch (musb->port_mode) { case MUSB_PORT_MODE_HOST: status = musb_host_setup(musb, plat->power); - if (status < 0) - goto fail3; - status = musb_platform_set_mode(musb, MUSB_HOST); break; case MUSB_PORT_MODE_GADGET: status = musb_gadget_setup(musb); - if (status < 0) - goto fail3; - status = musb_platform_set_mode(musb, MUSB_PERIPHERAL); break; case MUSB_PORT_MODE_DUAL_ROLE: status = musb_host_setup(musb, plat->power); if (status < 0) goto fail3; status = musb_gadget_setup(musb); - if (status) { - musb_host_cleanup(musb); + if (status < 0) goto fail3; - } - status = musb_platform_set_mode(musb, MUSB_OTG); break; default: - dev_err(dev, "unsupported port mode %d\n", musb->port_mode); + dev_err(musb->controller, "unsupported port mode %d\n", musb->port_mode); break; } if (status < 0) goto fail3; - status = musb_init_debugfs(musb); - if (status < 0) - goto fail4; - - status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group); - if (status) - goto fail5; - - pm_runtime_put(musb->controller); + if (IS_ENABLED(CONFIG_USB_MUSB_HOST) && plat->mode == USB_DR_MODE_HOST) + musb_register(musb); return 0; -fail5: - musb_exit_debugfs(musb); - -fail4: - musb_gadget_cleanup(musb); - musb_host_cleanup(musb); - fail3: - cancel_work_sync(&musb->irq_work); - cancel_delayed_work_sync(&musb->recover_work); - cancel_delayed_work_sync(&musb->finish_resume_work); - cancel_delayed_work_sync(&musb->deassert_reset_work); - if (musb->dma_controller) - dma_controller_destroy(musb->dma_controller); -fail2_5: - pm_runtime_put_sync(musb->controller); - fail2: - if (musb->irq_wake) - device_init_wakeup(dev, 0); musb_platform_exit(musb); fail1: - pm_runtime_disable(musb->controller); dev_err(musb->controller, "musb_init_controller failed with status %d\n", status); @@ -2067,307 +1154,3 @@ fail0: return status; } - -/*-------------------------------------------------------------------------*/ - -/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just - * bridge to a platform device; this driver then suffices. - */ -static int musb_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int irq = platform_get_irq_byname(pdev, "mc"); - struct resource *iomem; - void __iomem *base; - - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem || irq <= 0) - return -ENODEV; - - base = devm_ioremap_resource(dev, iomem); - if (IS_ERR(base)) - return PTR_ERR(base); - - return musb_init_controller(dev, irq, base); -} - -static int musb_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct musb *musb = dev_to_musb(dev); - - /* this gets called on rmmod. - * - Host mode: host may still be active - * - Peripheral mode: peripheral is deactivated (or never-activated) - * - OTG mode: both roles are deactivated (or never-activated) - */ - musb_exit_debugfs(musb); - musb_shutdown(pdev); - - if (musb->dma_controller) - dma_controller_destroy(musb->dma_controller); - - cancel_work_sync(&musb->irq_work); - cancel_delayed_work_sync(&musb->recover_work); - cancel_delayed_work_sync(&musb->finish_resume_work); - cancel_delayed_work_sync(&musb->deassert_reset_work); - musb_free(musb); - device_init_wakeup(dev, 0); - return 0; -} - -#ifdef CONFIG_PM - -static void musb_save_context(struct musb *musb) -{ - int i; - void __iomem *musb_base = musb->mregs; - void __iomem *epio; - - musb->context.frame = musb_readw(musb_base, MUSB_FRAME); - musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); - musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); - musb->context.power = musb_readb(musb_base, MUSB_POWER); - musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); - musb->context.index = musb_readb(musb_base, MUSB_INDEX); - musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL); - - for (i = 0; i < musb->config->num_eps; ++i) { - struct musb_hw_ep *hw_ep; - - hw_ep = &musb->endpoints[i]; - if (!hw_ep) - continue; - - epio = hw_ep->regs; - if (!epio) - continue; - - musb_writeb(musb_base, MUSB_INDEX, i); - musb->context.index_regs[i].txmaxp = - musb_readw(epio, MUSB_TXMAXP); - musb->context.index_regs[i].txcsr = - musb_readw(epio, MUSB_TXCSR); - musb->context.index_regs[i].rxmaxp = - musb_readw(epio, MUSB_RXMAXP); - musb->context.index_regs[i].rxcsr = - musb_readw(epio, MUSB_RXCSR); - - if (musb->dyn_fifo) { - musb->context.index_regs[i].txfifoadd = - musb_read_txfifoadd(musb_base); - musb->context.index_regs[i].rxfifoadd = - musb_read_rxfifoadd(musb_base); - musb->context.index_regs[i].txfifosz = - musb_read_txfifosz(musb_base); - musb->context.index_regs[i].rxfifosz = - musb_read_rxfifosz(musb_base); - } - - musb->context.index_regs[i].txtype = - musb_readb(epio, MUSB_TXTYPE); - musb->context.index_regs[i].txinterval = - musb_readb(epio, MUSB_TXINTERVAL); - musb->context.index_regs[i].rxtype = - musb_readb(epio, MUSB_RXTYPE); - musb->context.index_regs[i].rxinterval = - musb_readb(epio, MUSB_RXINTERVAL); - - musb->context.index_regs[i].txfunaddr = - musb_read_txfunaddr(musb_base, i); - musb->context.index_regs[i].txhubaddr = - musb_read_txhubaddr(musb_base, i); - musb->context.index_regs[i].txhubport = - musb_read_txhubport(musb_base, i); - - musb->context.index_regs[i].rxfunaddr = - musb_read_rxfunaddr(musb_base, i); - musb->context.index_regs[i].rxhubaddr = - musb_read_rxhubaddr(musb_base, i); - musb->context.index_regs[i].rxhubport = - musb_read_rxhubport(musb_base, i); - } -} - -static void musb_restore_context(struct musb *musb) -{ - int i; - void __iomem *musb_base = musb->mregs; - void __iomem *ep_target_regs; - void __iomem *epio; - u8 power; - - musb_writew(musb_base, MUSB_FRAME, musb->context.frame); - musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); - musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); - - /* Don't affect SUSPENDM/RESUME bits in POWER reg */ - power = musb_readb(musb_base, MUSB_POWER); - power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; - musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); - power |= musb->context.power; - musb_writeb(musb_base, MUSB_POWER, power); - - musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); - musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); - musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); - musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); - - for (i = 0; i < musb->config->num_eps; ++i) { - struct musb_hw_ep *hw_ep; - - hw_ep = &musb->endpoints[i]; - if (!hw_ep) - continue; - - epio = hw_ep->regs; - if (!epio) - continue; - - musb_writeb(musb_base, MUSB_INDEX, i); - musb_writew(epio, MUSB_TXMAXP, - musb->context.index_regs[i].txmaxp); - musb_writew(epio, MUSB_TXCSR, - musb->context.index_regs[i].txcsr); - musb_writew(epio, MUSB_RXMAXP, - musb->context.index_regs[i].rxmaxp); - musb_writew(epio, MUSB_RXCSR, - musb->context.index_regs[i].rxcsr); - - if (musb->dyn_fifo) { - musb_write_txfifosz(musb_base, - musb->context.index_regs[i].txfifosz); - musb_write_rxfifosz(musb_base, - musb->context.index_regs[i].rxfifosz); - musb_write_txfifoadd(musb_base, - musb->context.index_regs[i].txfifoadd); - musb_write_rxfifoadd(musb_base, - musb->context.index_regs[i].rxfifoadd); - } - - musb_writeb(epio, MUSB_TXTYPE, - musb->context.index_regs[i].txtype); - musb_writeb(epio, MUSB_TXINTERVAL, - musb->context.index_regs[i].txinterval); - musb_writeb(epio, MUSB_RXTYPE, - musb->context.index_regs[i].rxtype); - musb_writeb(epio, MUSB_RXINTERVAL, - - musb->context.index_regs[i].rxinterval); - musb_write_txfunaddr(musb_base, i, - musb->context.index_regs[i].txfunaddr); - musb_write_txhubaddr(musb_base, i, - musb->context.index_regs[i].txhubaddr); - musb_write_txhubport(musb_base, i, - musb->context.index_regs[i].txhubport); - - ep_target_regs = - musb_read_target_reg_base(i, musb_base); - - musb_write_rxfunaddr(ep_target_regs, - musb->context.index_regs[i].rxfunaddr); - musb_write_rxhubaddr(ep_target_regs, - musb->context.index_regs[i].rxhubaddr); - musb_write_rxhubport(ep_target_regs, - musb->context.index_regs[i].rxhubport); - } - musb_writeb(musb_base, MUSB_INDEX, musb->context.index); -} - -static int musb_suspend(struct device *dev) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - - if (is_peripheral_active(musb)) { - /* FIXME force disconnect unless we know USB will wake - * the system up quickly enough to respond ... - */ - } else if (is_host_active(musb)) { - /* we know all the children are suspended; sometimes - * they will even be wakeup-enabled. - */ - } - - musb_save_context(musb); - - spin_unlock_irqrestore(&musb->lock, flags); - return 0; -} - -static int musb_resume_noirq(struct device *dev) -{ - struct musb *musb = dev_to_musb(dev); - - /* - * For static cmos like DaVinci, register values were preserved - * unless for some reason the whole soc powered down or the USB - * module got reset through the PSC (vs just being disabled). - * - * For the DSPS glue layer though, a full register restore has to - * be done. As it shouldn't harm other platforms, we do it - * unconditionally. - */ - - musb_restore_context(musb); - - return 0; -} - -static int musb_runtime_suspend(struct device *dev) -{ - struct musb *musb = dev_to_musb(dev); - - musb_save_context(musb); - - return 0; -} - -static int musb_runtime_resume(struct device *dev) -{ - struct musb *musb = dev_to_musb(dev); - static int first = 1; - - /* - * When pm_runtime_get_sync called for the first time in driver - * init, some of the structure is still not initialized which is - * used in restore function. But clock needs to be - * enabled before any register access, so - * pm_runtime_get_sync has to be called. - * Also context restore without save does not make - * any sense - */ - if (!first) - musb_restore_context(musb); - first = 0; - - return 0; -} - -static const struct dev_pm_ops musb_dev_pm_ops = { - .suspend = musb_suspend, - .resume_noirq = musb_resume_noirq, - .runtime_suspend = musb_runtime_suspend, - .runtime_resume = musb_runtime_resume, -}; - -#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) -#else -#define MUSB_DEV_PM_OPS NULL -#endif - -static struct platform_driver musb_driver = { - .driver = { - .name = (char *)musb_driver_name, - .bus = &platform_bus_type, - .owner = THIS_MODULE, - .pm = MUSB_DEV_PM_OPS, - }, - .probe = musb_probe, - .remove = musb_remove, - .shutdown = musb_shutdown, -}; - -module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 414e57a984..46265d6190 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -35,19 +35,10 @@ #ifndef __MUSB_CORE_H__ #define __MUSB_CORE_H__ -#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/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb.h> -#include <linux/usb/otg.h> -#include <linux/usb/musb.h> -#include <linux/phy/phy.h> -#include <linux/workqueue.h> +#include <poller.h> +#include <notifier.h> +#include <usb/usb.h> +#include <usb/phy.h> struct musb; struct musb_hw_ep; @@ -63,14 +54,12 @@ struct musb_ep; #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" -#include <linux/usb/hcd.h> #include "musb_host.h" /* NOTE: otg and peripheral-only state machines start at B_IDLE. @@ -191,13 +180,13 @@ struct musb_platform_ops { void (*disable)(struct musb *musb); int (*set_mode)(struct musb *musb, u8 mode); - void (*try_idle)(struct musb *musb, unsigned long timeout); + void (*try_idle)(struct musb *musb, uint64_t timeout); int (*reset)(struct musb *musb); int (*vbus_status)(struct musb *musb); void (*set_vbus)(struct musb *musb, int on); - int (*adjust_channel_params)(struct dma_channel *channel, + int (*adjust_channel_params)(/*struct dma_channel *channel,*/ u16 packet_sz, u8 *mode, dma_addr_t *dma_addr, u32 *len); }; @@ -285,6 +274,25 @@ struct musb_context_registers { struct musb_csr_regs index_regs[MUSB_C_NUM_EPS]; }; +struct usb_phy; +struct usb_otg; + +/* + * Allocated per bus (tree of devices) we have: + */ +struct usb_bus { + u8 otg_port; /* 0, or number of OTG/HNP port */ + unsigned is_b_host:1; /* true during some HNP roleswitches */ + unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ +}; + +struct usb_hcd { + struct usb_bus self; + void *hcd_priv; +}; + +#define to_musb(ptr) container_of(ptr, struct musb, host) + /* * struct musb - Driver instance data. */ @@ -293,13 +301,8 @@ struct musb { spinlock_t lock; const struct musb_platform_ops *ops; - struct musb_context_registers context; - irqreturn_t (*isr)(int, void *); - struct work_struct irq_work; - struct delayed_work recover_work; - struct delayed_work deassert_reset_work; - struct delayed_work finish_resume_work; + int (*isr)(struct musb *); u16 hwvers; u16 intrrxe; @@ -309,7 +312,7 @@ struct musb { u32 port1_status; - unsigned long rh_timer; + uint64_t rh_timer; enum musb_h_ep0_state ep0_stage; @@ -325,12 +328,11 @@ struct musb { 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 poller_async otg_timer; struct dma_controller *dma_controller; - struct device *controller; + struct device_d *controller; void __iomem *ctrl_base; void __iomem *mregs; @@ -339,7 +341,6 @@ struct musb { dma_addr_t async; dma_addr_t sync; void __iomem *sync_va; - u8 tusb_revision; #endif /* passed down from chip/board specific irq handlers */ @@ -347,8 +348,9 @@ struct musb { u16 int_rx; u16 int_tx; + //struct device_d *phydev; + struct usb_host host; struct usb_phy *xceiv; - struct phy *phy; int nIrq; unsigned irq_wake:1; @@ -369,7 +371,6 @@ struct musb { 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; @@ -427,11 +428,7 @@ struct musb { unsigned double_buffer_not_ok:1; struct musb_hdrc_config *config; - - int xceiv_old_state; -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_root; -#endif + int host_speed; }; static inline struct musb *gadget_to_musb(struct usb_gadget *g) @@ -518,7 +515,7 @@ 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 int musb_interrupt(struct musb *); extern void musb_hnp_stop(struct musb *musb); @@ -540,16 +537,8 @@ static inline void musb_platform_disable(struct musb *musb) 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) + uint64_t timeout) { if (musb->ops->try_idle) musb->ops->try_idle(musb, timeout); @@ -587,4 +576,10 @@ static inline int musb_platform_exit(struct musb *musb) return musb->ops->exit(musb); } +struct musb_hdrc_platform_data; + +int musb_init_controller(struct musb *musb, struct musb_hdrc_platform_data *plat); +int musb_register(struct musb *data); +int musb_init(struct usb_host *host); + #endif /* __MUSB_CORE_H__ */ diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 1d44faa862..1345a4ff04 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -129,7 +129,6 @@ struct dma_channel { size_t actual_len; enum dma_channel_status status; bool desired_mode; - bool rx_packet_done; }; /* diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index c791ba5da9..36a316ab37 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -29,27 +29,19 @@ * da8xx.c would be merged to this file after testing. */ -#include <linux/io.h> +#include <common.h> +#include <init.h> +#include <clock.h> +#include <usb/usb.h> +#include <usb/musb.h> +#include <malloc.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/usb/usb_phy_generic.h> -#include <linux/platform_data/usb-omap.h> -#include <linux/sizes.h> - -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/usb/of.h> - -#include <linux/debugfs.h> +#include <linux/barebox-wrapper.h> #include "musb_core.h" +#include "phy-am335x.h" -static const struct of_device_id musb_dsps_of_match[]; +static __maybe_unused struct of_device_id musb_dsps_dt_ids[]; /** * avoid using musb_readx()/musb_writex() as glue layer should not be @@ -92,8 +84,6 @@ struct dsps_musb_wrapper { u16 coreintr_status; u16 phy_utmi; u16 mode; - u16 tx_mode; - u16 rx_mode; /* bit positions for control */ unsigned reset:5; @@ -117,103 +107,36 @@ struct dsps_musb_wrapper { /* bit positions for mode */ unsigned iddig:5; - unsigned iddig_mux:5; /* miscellaneous stuff */ u8 poll_seconds; }; -/* - * register shadow for suspend - */ -struct dsps_context { - u32 control; - u32 epintr; - u32 coreintr; - u32 phy_utmi; - u32 mode; - u32 tx_mode; - u32 rx_mode; -}; - /** * DSPS glue structure. */ struct dsps_glue { - struct device *dev; - struct platform_device *musb; /* child musb pdev */ + struct device_d *dev; + void __iomem *base; + unsigned long flags; + enum musb_mode mode; + struct musb musb; + struct musb_hdrc_config config; const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ - struct timer_list timer; /* otg_workaround timer */ - unsigned long last_timer; /* last timer data for each instance */ - bool sw_babble_enabled; - - struct dsps_context context; - struct debugfs_regset32 regset; - struct dentry *dbgfs_root; -}; - -static const struct debugfs_reg32 dsps_musb_regs[] = { - { "revision", 0x00 }, - { "control", 0x14 }, - { "status", 0x18 }, - { "eoi", 0x24 }, - { "intr0_stat", 0x30 }, - { "intr1_stat", 0x34 }, - { "intr0_set", 0x38 }, - { "intr1_set", 0x3c }, - { "txmode", 0x70 }, - { "rxmode", 0x74 }, - { "autoreq", 0xd0 }, - { "srpfixtime", 0xd4 }, - { "tdown", 0xd8 }, - { "phy_utmi", 0xe0 }, - { "mode", 0xe8 }, + struct poller_async timer; /* otg_workaround timer */ + uint64_t last_timer; /* last timer data for each instance */ + struct device_d otg_dev; + uint32_t otgmode; + struct musb_hdrc_platform_data pdata; }; -static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - - 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", - usb_otg_state_string(musb->xceiv->state)); - del_timer(&glue->timer); - glue->last_timer = jiffies; - return; - } - if (musb->port_mode != MUSB_PORT_MODE_DUAL_ROLE) - return; - - if (!musb->g.dev.driver) - return; - - if (time_after(glue->last_timer, timeout) && - timer_pending(&glue->timer)) { - dev_dbg(musb->controller, - "Longer idle timer already pending, ignoring...\n"); - return; - } - glue->last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - usb_otg_state_string(musb->xceiv->state), - jiffies_to_msecs(timeout - jiffies)); - mod_timer(&glue->timer, timeout); -} - /** * dsps_musb_enable - enable interrupts */ static void dsps_musb_enable(struct musb *musb) { - struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct device_d *dev = musb->controller; + struct device_d *pdev = dev; + struct dsps_glue *glue = pdev->priv; const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base = musb->ctrl_base; u32 epmask, coremask; @@ -228,7 +151,6 @@ static void dsps_musb_enable(struct musb *musb) /* Force the DRVVBUS IRQ so we can start polling for ID change. */ dsps_writel(reg_base, wrp->coreintr_set, (1 << wrp->drvvbus) << wrp->usb_shift); - dsps_musb_try_idle(musb, 0); } /** @@ -236,9 +158,9 @@ static void dsps_musb_enable(struct musb *musb) */ static void dsps_musb_disable(struct musb *musb) { - struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct device_d *dev = musb->controller; + struct device_d *pdev = dev; + struct dsps_glue *glue = pdev->priv; const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base = musb->ctrl_base; @@ -248,62 +170,11 @@ static void dsps_musb_disable(struct musb *musb) dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); } -static void otg_timer(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - void __iomem *mregs = musb->mregs; - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - const struct dsps_musb_wrapper *wrp = glue->wrp; - u8 devctl; - unsigned long flags; - int skip_session = 0; - - /* - * 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, - usb_otg_state_string(musb->xceiv->state)); - - spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { - case OTG_STATE_A_WAIT_BCON: - dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); - skip_session = 1; - /* fall */ - - case OTG_STATE_A_IDLE: - case OTG_STATE_B_IDLE: - 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); - } - if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) - dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); - 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; - default: - break; - } - spin_unlock_irqrestore(&musb->lock, flags); -} - -static irqreturn_t dsps_interrupt(int irq, void *hci) +static irqreturn_t dsps_interrupt(struct musb *musb) { - struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); + struct device_d *dev = musb->controller; + struct dsps_glue *glue = dev->priv; const struct dsps_musb_wrapper *wrp = glue->wrp; unsigned long flags; irqreturn_t ret = IRQ_NONE; @@ -330,325 +201,75 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", usbintr, epintr); - /* - * 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 (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) { - pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); - - /* - * When a babble condition occurs, the musb controller removes - * the session and is no longer in host mode. Hence, all - * devices connected to its root hub get disconnected. - * - * Hand this error down to the musb core isr, so it can - * recover. - */ - musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; - musb->int_tx = musb->int_rx = 0; - } - - 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 = 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 (drvvbus) { - 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", - usb_otg_state_string(musb->xceiv->state), - err ? " ERROR" : "", - devctl); - ret = IRQ_HANDLED; - } if (musb->int_tx || musb->int_rx || musb->int_usb) ret |= musb_interrupt(musb); - /* Poll for ID change in OTG port mode */ - if (musb->xceiv->state == OTG_STATE_B_IDLE && - musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); out: spin_unlock_irqrestore(&musb->lock, flags); return ret; } -static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) -{ - struct dentry *root; - struct dentry *file; - char buf[128]; - - sprintf(buf, "%s.dsps", dev_name(musb->controller)); - root = debugfs_create_dir(buf, NULL); - if (!root) - return -ENOMEM; - glue->dbgfs_root = root; - - glue->regset.regs = dsps_musb_regs; - glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs); - glue->regset.base = musb->ctrl_base; - - file = debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset); - if (!file) { - debugfs_remove_recursive(root); - return -ENOMEM; - } - return 0; -} - static int dsps_musb_init(struct musb *musb) { - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - struct platform_device *parent = to_platform_device(dev->parent); + struct device_d *dev = musb->controller; + struct dsps_glue *glue = dev->priv; const struct dsps_musb_wrapper *wrp = glue->wrp; - void __iomem *reg_base; - struct resource *r; - u32 rev, val; - int ret; - - r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); - if (!r) - return -EINVAL; - - reg_base = devm_ioremap_resource(dev, r); - if (IS_ERR(reg_base)) - return PTR_ERR(reg_base); - musb->ctrl_base = reg_base; + u32 rev, val, mode; - /* NOP driver needs change if supporting dual instance */ - musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); + musb->xceiv = am335x_get_usb_phy(); if (IS_ERR(musb->xceiv)) return PTR_ERR(musb->xceiv); /* Returns zero if e.g. not clocked */ - rev = dsps_readl(reg_base, wrp->revision); + rev = dsps_readl(musb->ctrl_base, wrp->revision); if (!rev) return -ENODEV; usb_phy_init(musb->xceiv); - setup_timer(&glue->timer, otg_timer, (unsigned long) musb); /* Reset the musb */ - dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); + dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); musb->isr = dsps_interrupt; /* reset the otgdisable bit, needed for host mode to work */ - val = dsps_readl(reg_base, wrp->phy_utmi); + val = dsps_readl(musb->ctrl_base, wrp->phy_utmi); val &= ~(1 << wrp->otg_disable); dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); - /* - * Check whether the dsps version has babble control enabled. - * In latest silicon revision the babble control logic is enabled. - * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control - * logic enabled. - */ - val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); - if (val == MUSB_BABBLE_RCV_DISABLE) { - glue->sw_babble_enabled = true; - val |= MUSB_BABBLE_SW_SESSION_CTRL; - dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); + mode = dsps_readl(musb->ctrl_base, wrp->mode); + + switch (musb->port_mode) { + case MUSB_PORT_MODE_HOST: + mode &= ~0x100; + break; + case MUSB_PORT_MODE_GADGET: + mode |= 0x100; + break; } - ret = dsps_musb_dbg_init(musb, glue); - if (ret) - return ret; + mode |= 0x80; + dsps_writel(musb->ctrl_base, wrp->mode, mode); /* IDDIG=0, IDDIG_MUX=1 */ return 0; } static int dsps_musb_exit(struct musb *musb) { - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - - del_timer_sync(&glue->timer); usb_phy_shutdown(musb->xceiv); - debugfs_remove_recursive(glue->dbgfs_root); - - return 0; -} - -static int dsps_musb_set_mode(struct musb *musb, u8 mode) -{ - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - const struct dsps_musb_wrapper *wrp = glue->wrp; - void __iomem *ctrl_base = musb->ctrl_base; - u32 reg; - - reg = dsps_readl(ctrl_base, wrp->mode); - - switch (mode) { - case MUSB_HOST: - reg &= ~(1 << wrp->iddig); - - /* - * if we're setting mode to host-only or device-only, we're - * going to ignore whatever the PHY sends us and just force - * ID pin status by SW - */ - reg |= (1 << wrp->iddig_mux); - - dsps_writel(ctrl_base, wrp->mode, reg); - dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); - break; - case MUSB_PERIPHERAL: - reg |= (1 << wrp->iddig); - - /* - * if we're setting mode to host-only or device-only, we're - * going to ignore whatever the PHY sends us and just force - * ID pin status by SW - */ - reg |= (1 << wrp->iddig_mux); - - dsps_writel(ctrl_base, wrp->mode, reg); - break; - case MUSB_OTG: - dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); - break; - default: - dev_err(glue->dev, "unsupported mode %d\n", mode); - return -EINVAL; - } - return 0; } -static bool sw_babble_control(struct musb *musb) -{ - u8 babble_ctl; - bool session_restart = false; - - babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); - dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", - babble_ctl); - /* - * check line monitor flag to check whether babble is - * due to noise - */ - dev_dbg(musb->controller, "STUCK_J is %s\n", - babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset"); - - if (babble_ctl & MUSB_BABBLE_STUCK_J) { - int timeout = 10; - - /* - * babble is due to noise, then set transmit idle (d7 bit) - * to resume normal operation - */ - babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); - babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; - dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); - - /* wait till line monitor flag cleared */ - dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); - do { - babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); - udelay(1); - } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); - - /* check whether stuck_at_j bit cleared */ - if (babble_ctl & MUSB_BABBLE_STUCK_J) { - /* - * real babble condition has occurred - * restart the controller to start the - * session again - */ - dev_dbg(musb->controller, "J not cleared, misc (%x)\n", - babble_ctl); - session_restart = true; - } - } else { - session_restart = true; - } - - return session_restart; -} - -static int dsps_musb_reset(struct musb *musb) -{ - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - const struct dsps_musb_wrapper *wrp = glue->wrp; - int session_restart = 0; - - if (glue->sw_babble_enabled) - session_restart = sw_babble_control(musb); - /* - * In case of new silicon version babble condition can be recovered - * without resetting the MUSB. But for older silicon versions, MUSB - * reset is needed - */ - if (session_restart || !glue->sw_babble_enabled) { - dev_info(musb->controller, "Restarting MUSB to recover from Babble\n"); - dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); - usleep_range(100, 200); - usb_phy_shutdown(musb->xceiv); - usleep_range(100, 200); - usb_phy_init(musb->xceiv); - session_restart = 1; - } - - return !session_restart; -} - static struct musb_platform_ops dsps_ops = { .init = dsps_musb_init, .exit = dsps_musb_exit, .enable = dsps_musb_enable, .disable = dsps_musb_disable, - - .try_idle = dsps_musb_try_idle, - .set_mode = dsps_musb_set_mode, - .reset = dsps_musb_reset, }; -static u64 musb_dmamask = DMA_BIT_MASK(32); - static int get_int_prop(struct device_node *dn, const char *s) { int ret; @@ -660,11 +281,11 @@ static int get_int_prop(struct device_node *dn, const char *s) return val; } -static int get_musb_port_mode(struct device *dev) +static int get_musb_port_mode(struct device_d *dev) { enum usb_dr_mode mode; - mode = of_usb_get_dr_mode(dev->of_node); + mode = of_usb_get_dr_mode(dev->device_node, NULL); switch (mode) { case USB_DR_MODE_HOST: return MUSB_PORT_MODE_HOST; @@ -675,153 +296,122 @@ static int get_musb_port_mode(struct device *dev) case USB_DR_MODE_UNKNOWN: case USB_DR_MODE_OTG: default: + if (!IS_ENABLED(CONFIG_USB_MUSB_HOST)) + return MUSB_PORT_MODE_GADGET; + if (!IS_ENABLED(CONFIG_USB_MUSB_GADGET)) + return MUSB_PORT_MODE_HOST; return MUSB_PORT_MODE_DUAL_ROLE; } } -static int dsps_create_musb_pdev(struct dsps_glue *glue, - struct platform_device *parent) +static int dsps_set_mode(struct param_d *param, void *priv) { - struct musb_hdrc_platform_data pdata; - struct resource resources[2]; - struct resource *res; - struct device *dev = &parent->dev; - struct musb_hdrc_config *config; - struct platform_device *musb; - struct device_node *dn = parent->dev.of_node; - int ret; + struct dsps_glue *glue = priv; - memset(resources, 0, sizeof(resources)); - res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc"); - if (!res) { - dev_err(dev, "failed to get memory.\n"); - return -EINVAL; - } - resources[0] = *res; + if (glue->pdata.mode != MUSB_PORT_MODE_DUAL_ROLE) + return -EBUSY; - res = platform_get_resource_byname(parent, IORESOURCE_IRQ, "mc"); - if (!res) { - dev_err(dev, "failed to get irq.\n"); + switch (glue->otgmode) { + case 0: + default: return -EINVAL; - } - resources[1] = *res; - - /* allocate the child platform device */ - musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); - if (!musb) { - dev_err(dev, "failed to allocate musb device\n"); - return -ENOMEM; + case 1: + glue->pdata.mode = MUSB_PORT_MODE_HOST; + break; + case 2: + glue->pdata.mode = MUSB_PORT_MODE_GADGET; + break; } - musb->dev.parent = dev; - musb->dev.dma_mask = &musb_dmamask; - musb->dev.coherent_dma_mask = musb_dmamask; - musb->dev.of_node = of_node_get(dn); + return musb_init_controller(&glue->musb, &glue->pdata); +} - glue->musb = musb; +static const char *dsps_mode_names[] = { + "otg", "host", "peripheral" +}; - ret = platform_device_add_resources(musb, resources, - ARRAY_SIZE(resources)); - if (ret) { - dev_err(dev, "failed to add resources\n"); - goto err; - } +static int dsps_register_otg_device(struct dsps_glue *glue) +{ + int ret; - config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL); - if (!config) { - dev_err(dev, "failed to allocate musb hdrc config\n"); - ret = -ENOMEM; - goto err; - } - pdata.config = config; - pdata.platform_ops = &dsps_ops; + strcpy(glue->otg_dev.name, "otg"); + glue->otg_dev.id = DEVICE_ID_DYNAMIC, + glue->otg_dev.parent = glue->dev; - config->num_eps = get_int_prop(dn, "mentor,num-eps"); - config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); - config->host_port_deassert_reset_at_resume = 1; - pdata.mode = get_musb_port_mode(dev); - /* DT keeps this entry in mA, musb expects it as per USB spec */ - pdata.power = get_int_prop(dn, "mentor,power") / 2; - config->multipoint = of_property_read_bool(dn, "mentor,multipoint"); - - ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); - if (ret) { - dev_err(dev, "failed to add platform_data\n"); - goto err; - } + ret = register_device(&glue->otg_dev); + if (ret) + return ret; - ret = platform_device_add(musb); - if (ret) { - dev_err(dev, "failed to register musb device\n"); - goto err; - } + dev_add_param_enum(&glue->otg_dev, "mode", + dsps_set_mode, NULL, &glue->otgmode, + dsps_mode_names, ARRAY_SIZE(dsps_mode_names), glue); return 0; - -err: - platform_device_put(musb); - return ret; } -static int dsps_probe(struct platform_device *pdev) +static int dsps_probe(struct device_d *dev) { - const struct of_device_id *match; + struct musb_hdrc_platform_data *pdata; + struct musb_hdrc_config *config; + struct device_node *dn = dev->device_node; const struct dsps_musb_wrapper *wrp; struct dsps_glue *glue; int ret; - if (!strcmp(pdev->name, "musb-hdrc")) - return -ENODEV; + ret = dev_get_drvdata(dev, (unsigned long *)&wrp); + if (ret) + return ret; - match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); - if (!match) { - dev_err(&pdev->dev, "fail to get matching of_match struct\n"); - return -EINVAL; + if (!IS_ENABLED(CONFIG_USB_MUSB_HOST) && + !IS_ENABLED(CONFIG_USB_MUSB_GADGET)) { + dev_err(dev, "Both host and device driver disabled.\n"); + return -ENODEV; } - wrp = match->data; /* allocate glue */ - glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { - dev_err(&pdev->dev, "unable to allocate glue memory\n"); + dev_err(dev, "unable to allocate glue memory\n"); return -ENOMEM; } - glue->dev = &pdev->dev; + glue->dev = dev; glue->wrp = wrp; - platform_set_drvdata(pdev, glue); - pm_runtime_enable(&pdev->dev); + dev->priv = glue; - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "pm_runtime_get_sync FAILED"); - goto err2; - } + pdata = &glue->pdata; - ret = dsps_create_musb_pdev(glue, pdev); - if (ret) - goto err3; + glue->musb.mregs = dev_request_mem_region(dev, 0); + if (IS_ERR(glue->musb.mregs)) + return PTR_ERR(glue->musb.mregs); - return 0; + glue->musb.ctrl_base = dev_request_mem_region(dev, 1); + if (IS_ERR(glue->musb.ctrl_base)) + return PTR_ERR(glue->musb.ctrl_base); -err3: - pm_runtime_put(&pdev->dev); -err2: - pm_runtime_disable(&pdev->dev); - return ret; -} + glue->musb.controller = dev; -static int dsps_remove(struct platform_device *pdev) -{ - struct dsps_glue *glue = platform_get_drvdata(pdev); + config = &glue->config; - platform_device_unregister(glue->musb); + pdata->config = config; + pdata->platform_ops = &dsps_ops; - /* disable usbss clocks */ - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); + config->num_eps = get_int_prop(dn, "mentor,num-eps"); + config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); - return 0; + pdata->mode = get_musb_port_mode(dev); + /* DT keeps this entry in mA, musb expects it as per USB spec */ + pdata->power = get_int_prop(dn, "mentor,power") / 2; + config->multipoint = of_property_read_bool(dn, "mentor,multipoint"); + + if (pdata->mode == MUSB_PORT_MODE_DUAL_ROLE) { + ret = dsps_register_otg_device(glue); + if (ret) + return ret; + return 0; + } + + return musb_init_controller(&glue->musb, pdata); } static const struct dsps_musb_wrapper am33xx_driver_data = { @@ -836,12 +426,9 @@ static const struct dsps_musb_wrapper am33xx_driver_data = { .coreintr_status = 0x34, .phy_utmi = 0xe0, .mode = 0xe8, - .tx_mode = 0x70, - .rx_mode = 0x74, .reset = 0, .otg_disable = 21, .iddig = 8, - .iddig_mux = 7, .usb_shift = 0, .usb_mask = 0x1ff, .usb_bitmap = (0x1ff << 0), @@ -855,66 +442,23 @@ static const struct dsps_musb_wrapper am33xx_driver_data = { .poll_seconds = 2, }; -static const struct of_device_id musb_dsps_of_match[] = { - { .compatible = "ti,musb-am33xx", - .data = (void *) &am33xx_driver_data, }, - { }, +static __maybe_unused struct of_device_id musb_dsps_dt_ids[] = { + { + .compatible = "ti,musb-am33xx", + .data = (unsigned long) &am33xx_driver_data, + }, { + /* sentinel */ + }, }; -MODULE_DEVICE_TABLE(of, musb_dsps_of_match); - -#ifdef CONFIG_PM_SLEEP -static int dsps_suspend(struct device *dev) -{ - struct dsps_glue *glue = dev_get_drvdata(dev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - struct musb *musb = platform_get_drvdata(glue->musb); - void __iomem *mbase = musb->ctrl_base; - glue->context.control = dsps_readl(mbase, wrp->control); - glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); - glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); - glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); - glue->context.mode = dsps_readl(mbase, wrp->mode); - glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); - glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); - - return 0; -} - -static int dsps_resume(struct device *dev) -{ - struct dsps_glue *glue = dev_get_drvdata(dev); - const struct dsps_musb_wrapper *wrp = glue->wrp; - struct musb *musb = platform_get_drvdata(glue->musb); - void __iomem *mbase = musb->ctrl_base; - - dsps_writel(mbase, wrp->control, glue->context.control); - dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); - dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); - dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); - dsps_writel(mbase, wrp->mode, glue->context.mode); - dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); - dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); - -static struct platform_driver dsps_usbss_driver = { - .probe = dsps_probe, - .remove = dsps_remove, - .driver = { - .name = "musb-dsps", - .pm = &dsps_pm_ops, - .of_match_table = musb_dsps_of_match, - }, +static struct driver_d dsps_usbss_driver = { + .name = "musb-dsps", + .probe = dsps_probe, + .of_compatible = DRV_OF_COMPAT(musb_dsps_dt_ids), }; +device_platform_driver(dsps_usbss_driver); 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"); - -module_platform_driver(dsps_usbss_driver); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d4aa779339..3f0ddd1875 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -33,108 +33,11 @@ * */ -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/timer.h> -#include <linux/module.h> -#include <linux/smp.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> - +#include <common.h> +#include <malloc.h> +#include <clock.h> #include "musb_core.h" - - -/* ----------------------------------------------------------------------- */ - -#define is_buffer_mapped(req) (is_dma_capable() && \ - (req->map_state != UN_MAPPED)) - -/* Maps the buffer to dma */ - -static inline void map_dma_buffer(struct musb_request *request, - struct musb *musb, struct musb_ep *musb_ep) -{ - int compatible = true; - struct dma_controller *dma = musb->dma_controller; - - request->map_state = UN_MAPPED; - - if (!is_dma_capable() || !musb_ep->dma) - return; - - /* Check if DMA engine can handle this request. - * DMA code must reject the USB request explicitly. - * Default behaviour is to map the request. - */ - if (dma->is_compatible) - compatible = dma->is_compatible(musb_ep->dma, - musb_ep->packet_sz, request->request.buf, - request->request.length); - if (!compatible) - return; - - if (request->request.dma == DMA_ADDR_INVALID) { - dma_addr_t dma_addr; - int ret; - - dma_addr = dma_map_single( - musb->controller, - request->request.buf, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - ret = dma_mapping_error(musb->controller, dma_addr); - if (ret) - return; - - request->request.dma = dma_addr; - request->map_state = MUSB_MAPPED; - } else { - dma_sync_single_for_device(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->map_state = PRE_MAPPED; - } -} - -/* Unmap the buffer from dma and maps it back to cpu */ -static inline void unmap_dma_buffer(struct musb_request *request, - struct musb *musb) -{ - struct musb_ep *musb_ep = request->ep; - - if (!is_buffer_mapped(request) || !musb_ep->dma) - return; - - if (request->request.dma == DMA_ADDR_INVALID) { - dev_vdbg(musb->controller, - "not unmapping a never mapped buffer\n"); - return; - } - if (request->map_state == MUSB_MAPPED) { - dma_unmap_single(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->request.dma = DMA_ADDR_INVALID; - } else { /* PRE_MAPPED */ - dma_sync_single_for_cpu(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - } - request->map_state = UN_MAPPED; -} +#include "musb_gadget.h" /* * Immediately complete a request. @@ -164,9 +67,6 @@ __acquires(ep->musb->lock) ep->busy = 1; spin_unlock(&musb->lock); - if (!dma_mapping_error(&musb->g.dev, request->dma)) - unmap_dma_buffer(req, musb); - if (request->status == 0) dev_dbg(musb->controller, "%s done request %p, %d/%d\n", ep->end_point.name, request, @@ -189,40 +89,10 @@ __acquires(ep->musb->lock) */ static void nuke(struct musb_ep *ep, const int status) { - struct musb *musb = ep->musb; struct musb_request *req = NULL; - void __iomem *epio = ep->musb->endpoints[ep->current_epnum].regs; ep->busy = 1; - if (is_dma_capable() && ep->dma) { - struct dma_controller *c = ep->musb->dma_controller; - int value; - - if (ep->is_in) { - /* - * The programming guide says that we must not clear - * the DMAMODE bit before DMAENAB, so we only - * clear it in the second write... - */ - musb_writew(epio, MUSB_TXCSR, - MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO); - musb_writew(epio, MUSB_TXCSR, - 0 | MUSB_TXCSR_FLUSHFIFO); - } else { - musb_writew(epio, MUSB_RXCSR, - 0 | MUSB_RXCSR_FLUSHFIFO); - musb_writew(epio, MUSB_RXCSR, - 0 | MUSB_RXCSR_FLUSHFIFO); - } - - value = c->channel_abort(ep->dma); - dev_dbg(musb->controller, "%s: abort DMA --> %d\n", - ep->name, value); - c->channel_release(ep->dma); - ep->dma = NULL; - } - while (!list_empty(&ep->req_list)) { req = list_first_entry(&ep->req_list, struct musb_request, list); musb_g_giveback(ep, &req->request, status); @@ -271,12 +141,6 @@ static void txstate(struct musb *musb, struct musb_request *req) return; } - /* we shouldn't get here while DMA is active ... but we do ... */ - if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "dma pending...\n"); - return; - } - /* read TXCSR before */ csr = musb_readw(epio, MUSB_TXCSR); @@ -300,124 +164,7 @@ static void txstate(struct musb *musb, struct musb_request *req) epnum, musb_ep->packet_sz, fifo_count, csr); -#ifndef CONFIG_MUSB_PIO_ONLY - if (is_buffer_mapped(req)) { - struct dma_controller *c = musb->dma_controller; - size_t request_size; - - /* setup DMA, then program endpoint CSR */ - request_size = min_t(size_t, request->length - request->actual, - musb_ep->dma->max_len); - - use_dma = (request->dma != DMA_ADDR_INVALID && request_size); - - /* MUSB_TXCSR_P_ISO is still set correctly */ - -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) - { - if (request_size < musb_ep->packet_sz) - musb_ep->dma->desired_mode = 0; - else - musb_ep->dma->desired_mode = 1; - - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - musb_ep->dma->desired_mode, - request->dma + request->actual, request_size); - if (use_dma) { - if (musb_ep->dma->desired_mode == 0) { - /* - * We must not clear the DMAMODE bit - * before the DMAENAB bit -- and the - * latter doesn't always get cleared - * before we get here... - */ - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB); - musb_writew(epio, MUSB_TXCSR, csr - | MUSB_TXCSR_P_WZC_BITS); - csr &= ~MUSB_TXCSR_DMAMODE; - csr |= (MUSB_TXCSR_DMAENAB | - MUSB_TXCSR_MODE); - /* against programming guide */ - } else { - csr |= (MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_MODE); - /* - * Enable Autoset according to table - * below - * bulk_split hb_mult Autoset_Enable - * 0 0 Yes(Normal) - * 0 >0 No(High BW ISO) - * 1 0 Yes(HS bulk) - * 1 >0 Yes(FS bulk) - */ - if (!musb_ep->hb_mult || - (musb_ep->hb_mult && - can_bulk_split(musb, - musb_ep->type))) - csr |= MUSB_TXCSR_AUTOSET; - } - csr &= ~MUSB_TXCSR_P_UNDERRUN; - - musb_writew(epio, MUSB_TXCSR, csr); - } - } - -#endif - if (is_cppi_enabled()) { - /* program endpoint CSR first, then setup DMA */ - csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); - csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | - MUSB_TXCSR_MODE; - musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS & - ~MUSB_TXCSR_P_UNDERRUN) | csr); - - /* ensure writebuffer is empty */ - csr = musb_readw(epio, MUSB_TXCSR); - - /* - * NOTE host side sets DMAENAB later than this; both are - * OK since the transfer dma glue (between CPPI and - * Mentor fifos) just tells CPPI it could start. Data - * only moves to the USB TX fifo when both fifos are - * ready. - */ - /* - * "mode" is irrelevant here; handle terminating ZLPs - * like PIO does, since the hardware RNDIS mode seems - * unreliable except for the - * last-packet-is-already-short case. - */ - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - 0, - request->dma + request->actual, - request_size); - if (!use_dma) { - c->channel_release(musb_ep->dma); - musb_ep->dma = NULL; - csr &= ~MUSB_TXCSR_DMAENAB; - musb_writew(epio, MUSB_TXCSR, csr); - /* invariant: prequest->buf is non-null */ - } - } else if (tusb_dma_omap()) - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - request->zero, - request->dma + request->actual, - request_size); - } -#endif - if (!use_dma) { - /* - * Unmap the dma buffer back to cpu if dma channel - * programming fails - */ - unmap_dma_buffer(req, musb); - musb_write_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; @@ -447,7 +194,6 @@ void musb_g_tx(struct musb *musb, u8 epnum) u8 __iomem *mbase = musb->mregs; struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_in; void __iomem *epio = musb->endpoints[epnum].regs; - struct dma_channel *dma; musb_ep_select(mbase, epnum); req = next_request(musb_ep); @@ -456,8 +202,6 @@ void musb_g_tx(struct musb *musb, u8 epnum) csr = musb_readw(epio, MUSB_TXCSR); dev_dbg(musb->controller, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr); - dma = is_dma_capable() ? musb_ep->dma : NULL; - /* * REVISIT: for high bandwidth, MUSB_TXCSR_P_INCOMPTX * probably rates reporting as a host error. @@ -478,31 +222,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) epnum, request); } - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - /* - * SHOULD NOT HAPPEN... has with CPPI though, after - * changing SENDSTALL (and other cases); harmless? - */ - dev_dbg(musb->controller, "%s dma still busy?\n", musb_ep->end_point.name); - return; - } - if (request) { - u8 is_dma = 0; - - if (dma && (csr & MUSB_TXCSR_DMAENAB)) { - is_dma = 1; - csr |= MUSB_TXCSR_P_WZC_BITS; - csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | - MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET); - musb_writew(epio, MUSB_TXCSR, csr); - /* Ensure writebuffer is empty. */ - csr = musb_readw(epio, MUSB_TXCSR); - request->actual += musb_ep->dma->actual_len; - dev_dbg(musb->controller, "TXCSR%d %04x, DMA off, len %zu, req %p\n", - epnum, csr, musb_ep->dma->actual_len, request); - } - /* * First, maybe a terminating short packet. Some DMA * engines might handle this by themselves. @@ -510,11 +230,6 @@ void musb_g_tx(struct musb *musb, u8 epnum) if ((request->zero && request->length && (request->length % musb_ep->packet_sz == 0) && (request->actual == request->length)) -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) - || (is_dma && (!dma->desired_mode || - (request->actual & - (musb_ep->packet_sz - 1)))) -#endif ) { /* * On DMA completion, FIFO may not be @@ -583,45 +298,12 @@ static void rxstate(struct musb *musb, struct musb_request *req) return; } - /* We shouldn't get here while DMA is active, but we do... */ - if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "DMA pending...\n"); - return; - } - if (csr & MUSB_RXCSR_P_SENDSTALL) { dev_dbg(musb->controller, "%s stalling, RXCSR %04x\n", musb_ep->end_point.name, csr); return; } - if (is_cppi_enabled() && is_buffer_mapped(req)) { - struct dma_controller *c = musb->dma_controller; - struct dma_channel *channel = musb_ep->dma; - - /* NOTE: CPPI won't actually stop advancing the DMA - * queue after short packet transfers, so this is almost - * always going to run as IRQ-per-packet DMA so that - * faults will be handled correctly. - */ - if (c->channel_program(channel, - musb_ep->packet_sz, - !request->short_not_ok, - request->dma + request->actual, - request->length - request->actual)) { - - /* make sure that if an rxpkt arrived after the irq, - * the cppi engine will be ready to take it as soon - * as DMA is enabled - */ - csr &= ~(MUSB_RXCSR_AUTOCLEAR - | MUSB_RXCSR_DMAMODE); - csr |= MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_WZC_BITS; - musb_writew(epio, MUSB_RXCSR, csr); - return; - } - } - if (csr & MUSB_RXCSR_RXPKTRDY) { fifo_count = musb_readw(epio, MUSB_RXCOUNT); @@ -637,132 +319,6 @@ static void rxstate(struct musb *musb, struct musb_request *req) use_mode_1 = 0; if (request->actual < request->length) { -#ifdef CONFIG_USB_INVENTRA_DMA - if (is_buffer_mapped(req)) { - struct dma_controller *c; - struct dma_channel *channel; - int use_dma = 0; - unsigned int transfer_size; - - c = musb->dma_controller; - channel = musb_ep->dma; - - /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in - * mode 0 only. So we do not get endpoint interrupts due to DMA - * completion. We only get interrupts from DMA controller. - * - * We could operate in DMA mode 1 if we knew the size of the tranfer - * in advance. For mass storage class, request->length = what the host - * sends, so that'd work. But for pretty much everything else, - * request->length is routinely more than what the host sends. For - * most these gadgets, end of is signified either by a short packet, - * or filling the last byte of the buffer. (Sending extra data in - * that last pckate should trigger an overflow fault.) But in mode 1, - * we don't get DMA completion interrupt for short packets. - * - * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1), - * to get endpoint interrupt on every DMA req, but that didn't seem - * to work reliably. - * - * REVISIT an updated g_file_storage can set req->short_not_ok, which - * then becomes usable as a runtime "use mode 1" hint... - */ - - /* Experimental: Mode1 works with mass storage use cases */ - if (use_mode_1) { - csr |= MUSB_RXCSR_AUTOCLEAR; - musb_writew(epio, MUSB_RXCSR, csr); - csr |= MUSB_RXCSR_DMAENAB; - musb_writew(epio, MUSB_RXCSR, csr); - - /* - * this special sequence (enabling and then - * disabling MUSB_RXCSR_DMAMODE) is required - * to get DMAReq to activate - */ - musb_writew(epio, MUSB_RXCSR, - csr | MUSB_RXCSR_DMAMODE); - musb_writew(epio, MUSB_RXCSR, csr); - - transfer_size = min_t(unsigned int, - request->length - - request->actual, - channel->max_len); - musb_ep->dma->desired_mode = 1; - } else { - if (!musb_ep->hb_mult && - musb_ep->hw_ep->rx_double_buffered) - csr |= MUSB_RXCSR_AUTOCLEAR; - csr |= MUSB_RXCSR_DMAENAB; - musb_writew(epio, MUSB_RXCSR, csr); - - transfer_size = min(request->length - request->actual, - (unsigned)fifo_count); - musb_ep->dma->desired_mode = 0; - } - - use_dma = c->channel_program( - channel, - musb_ep->packet_sz, - channel->desired_mode, - request->dma - + request->actual, - transfer_size); - - if (use_dma) - return; - } -#elif defined(CONFIG_USB_UX500_DMA) - if ((is_buffer_mapped(req)) && - (request->actual < request->length)) { - - struct dma_controller *c; - struct dma_channel *channel; - unsigned int transfer_size = 0; - - c = musb->dma_controller; - channel = musb_ep->dma; - - /* In case first packet is short */ - if (fifo_count < musb_ep->packet_sz) - transfer_size = fifo_count; - else if (request->short_not_ok) - transfer_size = min_t(unsigned int, - request->length - - request->actual, - channel->max_len); - else - transfer_size = min_t(unsigned int, - request->length - - request->actual, - (unsigned)fifo_count); - - csr &= ~MUSB_RXCSR_DMAMODE; - csr |= (MUSB_RXCSR_DMAENAB | - MUSB_RXCSR_AUTOCLEAR); - - musb_writew(epio, MUSB_RXCSR, csr); - - if (transfer_size <= musb_ep->packet_sz) { - musb_ep->dma->desired_mode = 0; - } else { - musb_ep->dma->desired_mode = 1; - /* Mode must be set after DMAENAB */ - csr |= MUSB_RXCSR_DMAMODE; - musb_writew(epio, MUSB_RXCSR, csr); - } - - if (c->channel_program(channel, - musb_ep->packet_sz, - channel->desired_mode, - request->dma - + request->actual, - transfer_size)) - - return; - } -#endif /* Mentor's DMA */ - len = request->length - request->actual; dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", musb_ep->end_point.name, @@ -771,38 +327,6 @@ static void rxstate(struct musb *musb, struct musb_request *req) fifo_count = min_t(unsigned, len, fifo_count); -#ifdef CONFIG_USB_TUSB_OMAP_DMA - if (tusb_dma_omap() && is_buffer_mapped(req)) { - struct dma_controller *c = musb->dma_controller; - struct dma_channel *channel = musb_ep->dma; - u32 dma_addr = request->dma + request->actual; - int ret; - - ret = c->channel_program(channel, - musb_ep->packet_sz, - channel->desired_mode, - dma_addr, - fifo_count); - if (ret) - return; - } -#endif - /* - * Unmap the dma buffer back to cpu if dma channel - * programming fails. This buffer is mapped if the - * channel allocation is successful - */ - if (is_buffer_mapped(req)) { - unmap_dma_buffer(req, musb); - - /* - * Clear DMAENAB and AUTOCLEAR for the - * PIO mode transfer - */ - csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); - musb_writew(epio, MUSB_RXCSR, csr); - } - musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; @@ -835,7 +359,6 @@ void musb_g_rx(struct musb *musb, u8 epnum) void __iomem *mbase = musb->mregs; struct musb_ep *musb_ep; void __iomem *epio = musb->endpoints[epnum].regs; - struct dma_channel *dma; struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; if (hw_ep->is_shared_fifo) @@ -852,10 +375,9 @@ void musb_g_rx(struct musb *musb, u8 epnum) request = &req->request; csr = musb_readw(epio, MUSB_RXCSR); - dma = is_dma_capable() ? musb_ep->dma : NULL; dev_dbg(musb->controller, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name, - csr, dma ? " (dma)" : "", request); + csr, "", request); if (csr & MUSB_RXCSR_P_SENTSTALL) { csr |= MUSB_RXCSR_P_WZC_BITS; @@ -878,71 +400,6 @@ void musb_g_rx(struct musb *musb, u8 epnum) dev_dbg(musb->controller, "%s, incomprx\n", musb_ep->end_point.name); } - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - /* "should not happen"; likely RXPKTRDY pending for DMA */ - dev_dbg(musb->controller, "%s busy, csr %04x\n", - musb_ep->end_point.name, csr); - return; - } - - if (dma && (csr & MUSB_RXCSR_DMAENAB)) { - csr &= ~(MUSB_RXCSR_AUTOCLEAR - | MUSB_RXCSR_DMAENAB - | MUSB_RXCSR_DMAMODE); - musb_writew(epio, MUSB_RXCSR, - MUSB_RXCSR_P_WZC_BITS | csr); - - request->actual += musb_ep->dma->actual_len; - - dev_dbg(musb->controller, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n", - epnum, csr, - musb_readw(epio, MUSB_RXCSR), - musb_ep->dma->actual_len, request); - -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ - defined(CONFIG_USB_UX500_DMA) - /* Autoclear doesn't clear RxPktRdy for short packets */ - if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered) - || (dma->actual_len - & (musb_ep->packet_sz - 1))) { - /* ack the read! */ - csr &= ~MUSB_RXCSR_RXPKTRDY; - musb_writew(epio, MUSB_RXCSR, csr); - } - - /* incomplete, and not short? wait for next IN packet */ - if ((request->actual < request->length) - && (musb_ep->dma->actual_len - == musb_ep->packet_sz)) { - /* In double buffer case, continue to unload fifo if - * there is Rx packet in FIFO. - **/ - csr = musb_readw(epio, MUSB_RXCSR); - if ((csr & MUSB_RXCSR_RXPKTRDY) && - hw_ep->rx_double_buffered) - goto exit; - return; - } -#endif - musb_g_giveback(musb_ep, request, 0); - /* - * In the giveback function the MUSB lock is - * released and acquired after sometime. During - * this time period the INDEX register could get - * changed by the gadget_queue function especially - * on SMP systems. Reselect the INDEX to be sure - * we are reading/modifying the right registers - */ - musb_ep_select(mbase, epnum); - - req = next_request(musb_ep); - if (!req) - return; - } -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ - defined(CONFIG_USB_UX500_DMA) -exit: -#endif /* Analyze request */ rxstate(musb, req); } @@ -1099,17 +556,6 @@ static int musb_gadget_enable(struct usb_ep *ep, musb_writew(regs, MUSB_RXCSR, csr); } - /* NOTE: all the I/O code _should_ work fine without DMA, in case - * for some reason you run out of channels here. - */ - if (is_dma_capable() && musb->dma_controller) { - struct dma_controller *c = musb->dma_controller; - - musb_ep->dma = c->channel_alloc(c, hw_ep, - (desc->bEndpointAddress & USB_DIR_IN)); - } else - musb_ep->dma = NULL; - musb_ep->desc = desc; musb_ep->busy = 0; musb_ep->wedged = 0; @@ -1123,11 +569,9 @@ static int musb_gadget_enable(struct usb_ep *ep, default: s = "iso"; break; } s; }), musb_ep->is_in ? "IN" : "OUT", - musb_ep->dma ? "dma, " : "", + "", musb_ep->packet_sz); - schedule_work(&musb->irq_work); - fail: spin_unlock_irqrestore(&musb->lock, flags); return status; @@ -1170,8 +614,6 @@ static int musb_gadget_disable(struct usb_ep *ep) /* abort all pending DMA and requests */ nuke(musb_ep, -ESHUTDOWN); - schedule_work(&musb->irq_work); - spin_unlock_irqrestore(&(musb->lock), flags); dev_dbg(musb->controller, "%s\n", musb_ep->end_point.name); @@ -1183,7 +625,7 @@ static int musb_gadget_disable(struct usb_ep *ep) * Allocate a request for an endpoint. * Reused by ep0 code. */ -struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) +struct usb_request *musb_alloc_request(struct usb_ep *ep) { struct musb_ep *musb_ep = to_musb_ep(ep); struct musb *musb = musb_ep->musb; @@ -1236,8 +678,7 @@ void musb_ep_restart(struct musb *musb, struct musb_request *req) rxstate(musb, req); } -static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) +static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req) { struct musb_ep *musb_ep; struct musb_request *request; @@ -1267,8 +708,6 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, request->epnum = musb_ep->current_epnum; request->tx = musb_ep->is_in; - map_dma_buffer(request, musb, musb_ep); - spin_lock_irqsave(&musb->lock, lockflags); /* don't queue if the ep is down */ @@ -1276,7 +715,6 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, dev_dbg(musb->controller, "req %p queued to %s while ep %s\n", req, ep->name, "disabled"); status = -ESHUTDOWN; - unmap_dma_buffer(request, musb); goto unlock; } @@ -1317,20 +755,8 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request) } /* if the hardware doesn't have the request, easy ... */ - if (musb_ep->req_list.next != &req->list || musb_ep->busy) + if (musb_ep->req_list.next != &req->list || musb_ep->busy) { musb_g_giveback(musb_ep, request, -ECONNRESET); - - /* ... else abort the dma transfer ... */ - else if (is_dma_capable() && musb_ep->dma) { - struct dma_controller *c = musb->dma_controller; - - musb_ep_select(musb->mregs, musb_ep->current_epnum); - if (c->channel_abort) - status = c->channel_abort(musb_ep->dma); - else - status = -EBUSY; - if (status == 0) - musb_g_giveback(musb_ep, request, -ECONNRESET); } else { /* NOTE: by sticking to easily tested hardware/driver states, * we leave counting of in-flight packets imprecise. @@ -1535,80 +961,6 @@ static int musb_gadget_get_frame(struct usb_gadget *gadget) return (int)musb_readw(musb->mregs, MUSB_FRAME); } -static int musb_gadget_wakeup(struct usb_gadget *gadget) -{ - struct musb *musb = gadget_to_musb(gadget); - void __iomem *mregs = musb->mregs; - unsigned long flags; - int status = -EINVAL; - u8 power, devctl; - int retries; - - spin_lock_irqsave(&musb->lock, flags); - - switch (musb->xceiv->state) { - case OTG_STATE_B_PERIPHERAL: - /* NOTE: OTG state machine doesn't include B_SUSPENDED; - * that's part of the standard usb 1.1 state machine, and - * doesn't affect OTG transitions. - */ - if (musb->may_wakeup && musb->is_suspended) - break; - goto done; - case OTG_STATE_B_IDLE: - /* Start SRP ... OTG not required. */ - devctl = musb_readb(mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "Sending SRP: devctl: %02x\n", devctl); - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(mregs, MUSB_DEVCTL, devctl); - devctl = musb_readb(mregs, MUSB_DEVCTL); - retries = 100; - while (!(devctl & MUSB_DEVCTL_SESSION)) { - devctl = musb_readb(mregs, MUSB_DEVCTL); - if (retries-- < 1) - break; - } - retries = 10000; - while (devctl & MUSB_DEVCTL_SESSION) { - devctl = musb_readb(mregs, MUSB_DEVCTL); - if (retries-- < 1) - break; - } - - spin_unlock_irqrestore(&musb->lock, flags); - otg_start_srp(musb->xceiv->otg); - spin_lock_irqsave(&musb->lock, flags); - - /* Block idling for at least 1s */ - musb_platform_try_idle(musb, - jiffies + msecs_to_jiffies(1 * HZ)); - - status = 0; - goto done; - default: - dev_dbg(musb->controller, "Unhandled wake: %s\n", - usb_otg_state_string(musb->xceiv->state)); - goto done; - } - - status = 0; - - power = musb_readb(mregs, MUSB_POWER); - power |= MUSB_POWER_RESUME; - musb_writeb(mregs, MUSB_POWER, power); - dev_dbg(musb->controller, "issue wakeup\n"); - - /* FIXME do this next chunk in a timer callback, no udelay */ - mdelay(2); - - power = musb_readb(mregs, MUSB_POWER); - power &= ~MUSB_POWER_RESUME; - musb_writeb(mregs, MUSB_POWER, power); -done: - spin_unlock_irqrestore(&musb->lock, flags); - return status; -} - static int musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered) { @@ -1635,20 +987,6 @@ static void musb_pullup(struct musb *musb, int is_on) musb_writeb(musb->mregs, MUSB_POWER, power); } -#if 0 -static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active) -{ - dev_dbg(musb->controller, "<= %s =>\n", __func__); - - /* - * FIXME iff driver's softconnect flag is set (as it is during probe, - * though that can clear it), just musb_pullup(). - */ - - return -EINVAL; -} -#endif - static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) { struct musb *musb = gadget_to_musb(gadget); @@ -1665,8 +1003,6 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) is_on = !!is_on; - pm_runtime_get_sync(musb->controller); - /* NOTE: this assumes we are sensing vbus; we'd rather * not pullup unless the B-session is active. */ @@ -1677,11 +1013,16 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) } spin_unlock_irqrestore(&musb->lock, flags); - pm_runtime_put(musb->controller); - return 0; } +static void musb_gadget_poll(struct usb_gadget *gadget) +{ + struct musb *musb = gadget_to_musb(gadget); + + musb->isr(musb); +} + static int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int musb_gadget_stop(struct usb_gadget *g, @@ -1689,13 +1030,13 @@ static int musb_gadget_stop(struct usb_gadget *g, static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, - .wakeup = musb_gadget_wakeup, .set_selfpowered = musb_gadget_set_self_powered, /* .vbus_session = musb_gadget_vbus_session, */ .vbus_draw = musb_gadget_vbus_draw, .pullup = musb_gadget_pullup, .udc_start = musb_gadget_start, .udc_stop = musb_gadget_stop, + .udc_poll = musb_gadget_poll, }; /* ----------------------------------------------------------------------- */ @@ -1791,16 +1132,11 @@ int musb_gadget_setup(struct musb *musb) musb->g.speed = USB_SPEED_UNKNOWN; MUSB_DEV_MODE(musb); - musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; /* this "gadget" abstracts/virtualizes the controller */ musb->g.name = musb_driver_name; -#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE) - musb->g.is_otg = 1; -#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET) + musb->g.is_otg = 0; -#endif musb_g_init_endpoints(musb); @@ -1814,7 +1150,6 @@ int musb_gadget_setup(struct musb *musb) return 0; err: musb->g.dev.parent = NULL; - device_unregister(&musb->g.dev); return status; } @@ -1840,7 +1175,6 @@ static int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct musb *musb = gadget_to_musb(g); - struct usb_otg *otg = musb->xceiv->otg; unsigned long flags; int retval = 0; @@ -1849,8 +1183,6 @@ static int musb_gadget_start(struct usb_gadget *g, goto err; } - pm_runtime_get_sync(musb->controller); - dev_dbg(musb->controller, "registering driver %s\n", driver->function); musb->softconnect = 0; @@ -1859,22 +1191,10 @@ static int musb_gadget_start(struct usb_gadget *g, spin_lock_irqsave(&musb->lock, flags); musb->is_active = 1; - otg_set_peripheral(otg, &musb->g); - musb->xceiv->state = OTG_STATE_B_IDLE; spin_unlock_irqrestore(&musb->lock, flags); musb_start(musb); - /* REVISIT: funcall to other code, which also - * handles power budgeting ... this way also - * ensures HdrcStart is indirectly called. - */ - if (musb->xceiv->last_event == USB_EVENT_ID) - musb_platform_set_vbus(musb, 1); - - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_put(musb->controller); - return 0; err: @@ -1931,9 +1251,6 @@ static int musb_gadget_stop(struct usb_gadget *g, struct musb *musb = gadget_to_musb(g); unsigned long flags; - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_get_sync(musb->controller); - /* * REVISIT always use otg_set_peripheral() here too; * this needs to shut down the OTG engine. @@ -1941,13 +1258,9 @@ static int musb_gadget_stop(struct usb_gadget *g, spin_lock_irqsave(&musb->lock, flags); - musb_hnp_stop(musb); - (void) musb_gadget_vbus_draw(&musb->g, 0); - musb->xceiv->state = OTG_STATE_UNDEFINED; stop_activity(musb, driver); - otg_set_peripheral(musb->xceiv->otg, NULL); dev_dbg(musb->controller, "unregistering driver %s\n", driver ? driver->function : "(removed)"); @@ -1963,8 +1276,6 @@ static int musb_gadget_stop(struct usb_gadget *g, * that currently misbehaves. */ - pm_runtime_put(musb->controller); - return 0; } @@ -1972,63 +1283,6 @@ static int musb_gadget_stop(struct usb_gadget *g, /* lifecycle operations called through plat_uds.c */ -void musb_g_resume(struct musb *musb) -{ - musb->is_suspended = 0; - switch (musb->xceiv->state) { - case OTG_STATE_B_IDLE: - break; - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_PERIPHERAL: - musb->is_active = 1; - if (musb->gadget_driver && musb->gadget_driver->resume) { - spin_unlock(&musb->lock); - musb->gadget_driver->resume(&musb->g); - spin_lock(&musb->lock); - } - break; - default: - WARNING("unhandled RESUME transition (%s)\n", - usb_otg_state_string(musb->xceiv->state)); - } -} - -/* called when SOF packets stop for 3+ msec */ -void musb_g_suspend(struct musb *musb) -{ - u8 devctl; - - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "devctl %02x\n", devctl); - - switch (musb->xceiv->state) { - case OTG_STATE_B_IDLE: - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - break; - case OTG_STATE_B_PERIPHERAL: - musb->is_suspended = 1; - if (musb->gadget_driver && musb->gadget_driver->suspend) { - spin_unlock(&musb->lock); - musb->gadget_driver->suspend(&musb->g); - spin_lock(&musb->lock); - } - break; - default: - /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ; - * A_PERIPHERAL may need care too - */ - WARNING("unhandled SUSPEND transition (%s)\n", - usb_otg_state_string(musb->xceiv->state)); - } -} - -/* Called during SRP */ -void musb_g_wakeup(struct musb *musb) -{ - musb_gadget_wakeup(&musb->g); -} - /* called when VBUS drops below session threshold, and in other cases */ void musb_g_disconnect(struct musb *musb) { @@ -2050,91 +1304,5 @@ void musb_g_disconnect(struct musb *musb) spin_lock(&musb->lock); } - switch (musb->xceiv->state) { - default: - dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", - usb_otg_state_string(musb->xceiv->state)); - musb->xceiv->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - break; - case OTG_STATE_A_PERIPHERAL: - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; - MUSB_HST_MODE(musb); - break; - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_HOST: - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_IDLE: - musb->xceiv->state = OTG_STATE_B_IDLE; - break; - case OTG_STATE_B_SRP_INIT: - break; - } - musb->is_active = 0; } - -void musb_g_reset(struct musb *musb) -__releases(musb->lock) -__acquires(musb->lock) -{ - void __iomem *mbase = musb->mregs; - u8 devctl = musb_readb(mbase, MUSB_DEVCTL); - u8 power; - - dev_dbg(musb->controller, "<== %s driver '%s'\n", - (devctl & MUSB_DEVCTL_BDEVICE) - ? "B-Device" : "A-Device", - musb->gadget_driver - ? musb->gadget_driver->driver.name - : NULL - ); - - /* report disconnect, if we didn't already (flushing EP state) */ - if (musb->g.speed != USB_SPEED_UNKNOWN) - musb_g_disconnect(musb); - - /* clear HR */ - else if (devctl & MUSB_DEVCTL_HR) - musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - - - /* what speed did we negotiate? */ - power = musb_readb(mbase, MUSB_POWER); - musb->g.speed = (power & MUSB_POWER_HSMODE) - ? USB_SPEED_HIGH : USB_SPEED_FULL; - - /* start in USB_STATE_DEFAULT */ - musb->is_active = 1; - musb->is_suspended = 0; - MUSB_DEV_MODE(musb); - musb->address = 0; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - - musb->may_wakeup = 0; - musb->g.b_hnp_enable = 0; - musb->g.a_alt_hnp_support = 0; - musb->g.a_hnp_support = 0; - - /* Normal reset, as B-Device; - * or else after HNP, as A-Device - */ - if (!musb->g.is_otg) { - /* USB device controllers that are not OTG compatible - * may not have DEVCTL register in silicon. - * In that case, do not rely on devctl for setting - * peripheral mode. - */ - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - musb->g.is_a_peripheral = 0; - } else if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - musb->g.is_a_peripheral = 0; - } else { - musb->xceiv->state = OTG_STATE_A_PERIPHERAL; - musb->g.is_a_peripheral = 1; - } - - /* start with default limits on VBUS power draw */ - (void) musb_gadget_vbus_draw(&musb->g, 8); -} diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index 0314dfc770..456c165cc7 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h @@ -36,9 +36,10 @@ #define __MUSB_GADGET_H #include <linux/list.h> +#include <usb/gadget.h> -#if IS_ENABLED(CONFIG_USB_MUSB_GADGET) || IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE) -extern irqreturn_t musb_g_ep0_irq(struct musb *); +#if IS_ENABLED(CONFIG_USB_MUSB_GADGET) +extern int 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 *); @@ -50,7 +51,7 @@ extern void musb_gadget_cleanup(struct musb *); extern int musb_gadget_setup(struct musb *); #else -static inline irqreturn_t musb_g_ep0_irq(struct musb *musb) +static inline int musb_g_ep0_irq(struct musb *musb) { return 0; } @@ -90,8 +91,7 @@ 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 struct usb_request *musb_alloc_request(struct usb_ep *ep); extern void musb_free_request(struct usb_ep *ep, struct usb_request *req); diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 2af45a0c89..feaa856451 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -33,14 +33,11 @@ * */ -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/timer.h> -#include <linux/spinlock.h> -#include <linux/device.h> -#include <linux/interrupt.h> - +#include <common.h> +#include <malloc.h> +#include <clock.h> #include "musb_core.h" +#include "musb_gadget.h" /* ep0 is always musb->endpoints[0].ep_in */ #define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) @@ -638,7 +635,6 @@ musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY); while ((musb_readw(regs, MUSB_CSR0) & MUSB_CSR0_RXPKTRDY) != 0) - cpu_relax(); musb->ackpend = 0; } else musb->ep0_state = MUSB_EP0_STAGE_RX; @@ -708,7 +704,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; break; default: - ERR("SetupEnd came in a wrong ep0stage %s\n", + dev_err(musb->controller, "SetupEnd came in a wrong ep0stage %s\n", decode_ep0stage(musb->ep0_state)); } csr = musb_readw(regs, MUSB_CSR0); @@ -801,7 +797,7 @@ setup: int handled = 0; if (len != 8) { - ERR("SETUP packet len %d != 8 ?\n", len); + dev_err(musb->controller, "SETUP packet len %d != 8 ?\n", len); break; } musb_read_setup(musb, &setup); @@ -925,7 +921,7 @@ static int musb_g_ep0_disable(struct usb_ep *e) } static int -musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) +musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r) { struct musb_ep *ep; struct musb_request *req; diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 855793d701..32a8f06529 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -33,15 +33,8 @@ * */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/list.h> -#include <linux/dma-mapping.h> - +#include <common.h> +#include <malloc.h> #include "musb_core.h" #include "musb_host.h" @@ -96,7 +89,7 @@ struct musb *hcd_to_musb(struct usb_hcd *hcd) { - return *(struct musb **) hcd->hcd_priv; + return (struct musb *) hcd->hcd_priv; } @@ -120,19 +113,21 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) if (csr != lastcsr) dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr); lastcsr = csr; - csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_TXPKTRDY; + csr |= MUSB_TXCSR_FLUSHFIFO; musb_writew(epio, MUSB_TXCSR, csr); csr = musb_readw(epio, MUSB_TXCSR); - if (WARN(retries-- < 1, - "Could not flush host TX%d fifo: csr: %04x\n", - ep->epnum, csr)) + if (!retries--) { + dev_warn(musb->controller, "Could not flush host TX%d fifo: csr: %04x\n", + ep->epnum, csr); return; + } mdelay(1); } } static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) { + struct musb *musb = ep->musb; void __iomem *epio = ep->regs; u16 csr; int retries = 5; @@ -147,7 +142,8 @@ static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) udelay(10); } while (--retries); - WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n", + if (!retries) + dev_warn(musb->controller, "Could not flush host TX%d fifo: csr: %04x\n", ep->epnum, csr); /* and reset for the next transfer */ @@ -232,12 +228,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) buf = urb->setup_packet; len = 8; break; - case USB_ENDPOINT_XFER_ISOC: - qh->iso_idx = 0; - qh->frame = 0; - offset = urb->iso_frame_desc[0].offset; - len = urb->iso_frame_desc[0].length; - break; default: /* bulk, interrupt */ /* actual_length may be nonzero on retry paths */ buf = urb->transfer_buffer + urb->actual_length; @@ -250,7 +240,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) ({char *s; switch (qh->type) { case USB_ENDPOINT_XFER_CONTROL: s = ""; break; case USB_ENDPOINT_XFER_BULK: s = "-bulk"; break; - case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; default: s = "-intr"; break; } s; }), epnum, buf + offset, len); @@ -265,7 +254,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) /* determine if the time is right for a periodic transfer */ switch (qh->type) { - case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: dev_dbg(musb->controller, "check whether there's still time for periodic Tx\n"); frame = musb_readw(mbase, MUSB_FRAME); @@ -294,8 +282,6 @@ start: if (!hw_ep->tx_channel) musb_h_tx_start(hw_ep); - else if (is_cppi_enabled() || tusb_dma_omap()) - musb_h_tx_dma_start(hw_ep); } } @@ -362,10 +348,6 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, case USB_ENDPOINT_XFER_INT: musb_save_toggle(qh, is_in, urb); break; - case USB_ENDPOINT_XFER_ISOC: - if (status == 0 && urb->error_count) - status = -EXDEV; - break; } qh->is_ready = 0; @@ -412,7 +394,6 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, break; } - case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: /* this is where periodic bandwidth should be * de-allocated if it's tracked and allocated; @@ -465,7 +446,6 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err) struct musb_hw_ep *hw_ep = musb->endpoints + epnum; void __iomem *epio = hw_ep->regs; struct musb_qh *qh = hw_ep->in_qh; - int pipe = urb->pipe; void *buffer = urb->transfer_buffer; /* musb_ep_select(mbase, epnum); */ @@ -475,34 +455,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err) urb->transfer_buffer_length); /* unload FIFO */ - if (usb_pipeisoc(pipe)) { - int status = 0; - struct usb_iso_packet_descriptor *d; - - if (iso_err) { - status = -EILSEQ; - urb->error_count++; - } - - d = urb->iso_frame_desc + qh->iso_idx; - buf = buffer + d->offset; - length = d->length; - if (rx_count > length) { - if (status == 0) { - status = -EOVERFLOW; - urb->error_count++; - } - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length); - do_flush = 1; - } else - length = rx_count; - urb->actual_length += length; - d->actual_length = length; - - d->status = status; - - /* see if we are done */ - done = (++qh->iso_idx >= urb->number_of_packets); + if (0) { } else { /* non-isoch */ buf = buffer + qh->offset; @@ -586,7 +539,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) } else { csr = musb_readw(ep->regs, MUSB_RXCSR); if (csr & MUSB_RXCSR_RXPKTRDY) - WARNING("rx%d, packet/%d ready?\n", ep->epnum, + dev_warn(musb->controller, "rx%d, packet/%d ready?\n", ep->epnum, musb_readw(ep->regs, MUSB_RXCOUNT)); musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); @@ -617,78 +570,6 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) ep->rx_reinit = 0; } -static bool musb_tx_dma_program(struct dma_controller *dma, - struct musb_hw_ep *hw_ep, struct musb_qh *qh, - struct urb *urb, u32 offset, u32 length) -{ - struct dma_channel *channel = hw_ep->tx_channel; - void __iomem *epio = hw_ep->regs; - u16 pkt_size = qh->maxpacket; - u16 csr; - u8 mode; - -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) - if (length > channel->max_len) - length = channel->max_len; - - csr = musb_readw(epio, MUSB_TXCSR); - if (length > pkt_size) { - mode = 1; - csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB; - /* autoset shouldn't be set in high bandwidth */ - /* - * Enable Autoset according to table - * below - * bulk_split hb_mult Autoset_Enable - * 0 1 Yes(Normal) - * 0 >1 No(High BW ISO) - * 1 1 Yes(HS bulk) - * 1 >1 Yes(FS bulk) - */ - if (qh->hb_mult == 1 || (qh->hb_mult > 1 && - can_bulk_split(hw_ep->musb, qh->type))) - csr |= MUSB_TXCSR_AUTOSET; - } else { - mode = 0; - csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); - csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ - } - channel->desired_mode = mode; - musb_writew(epio, MUSB_TXCSR, csr); -#else - if (!is_cppi_enabled() && !tusb_dma_omap()) - return false; - - channel->actual_len = 0; - - /* - * TX uses "RNDIS" mode automatically but needs help - * to identify the zero-length-final-packet case. - */ - mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; -#endif - - qh->segsize = length; - - /* - * Ensure the data reaches to main memory before starting - * DMA transfer - */ - wmb(); - - if (!dma->channel_program(channel, pkt_size, mode, - urb->transfer_dma + offset, length)) { - dma->channel_release(channel); - hw_ep->tx_channel = NULL; - - csr = musb_readw(epio, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); - musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS); - return false; - } - return true; -} - /* * Program an HDRC endpoint as per the given URB * Context: irqs blocked, controller lock held @@ -697,15 +578,11 @@ static void musb_ep_program(struct musb *musb, u8 epnum, struct urb *urb, int is_out, u8 *buf, u32 offset, u32 len) { - struct dma_controller *dma_controller; - struct dma_channel *dma_channel; - u8 dma_ok; void __iomem *mbase = musb->mregs; struct musb_hw_ep *hw_ep = musb->endpoints + epnum; void __iomem *epio = hw_ep->regs; struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out); u16 packet_sz = qh->maxpacket; - u8 use_dma = 1; u16 csr; dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s " @@ -719,30 +596,12 @@ static void musb_ep_program(struct musb *musb, u8 epnum, musb_ep_select(mbase, epnum); if (is_out && !len) { - use_dma = 0; csr = musb_readw(epio, MUSB_TXCSR); csr &= ~MUSB_TXCSR_DMAENAB; musb_writew(epio, MUSB_TXCSR, csr); hw_ep->tx_channel = NULL; } - /* candidate for DMA? */ - dma_controller = musb->dma_controller; - if (use_dma && is_dma_capable() && epnum && dma_controller) { - dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel; - if (!dma_channel) { - dma_channel = dma_controller->channel_alloc( - dma_controller, hw_ep, is_out); - if (is_out) - hw_ep->tx_channel = dma_channel; - else - hw_ep->rx_channel = dma_channel; - } - } else - dma_channel = NULL; - - /* make sure we clear DMAEnab, autoSet bits from previous run */ - /* OUT/transmit/EP0 or IN/receive? */ if (is_out) { u16 csr; @@ -838,35 +697,12 @@ static void musb_ep_program(struct musb *musb, u8 epnum, else load_count = min((u32) packet_sz, len); - if (dma_channel && musb_tx_dma_program(dma_controller, - hw_ep, qh, urb, offset, len)) - load_count = 0; - if (load_count) { /* PIO to load FIFO */ qh->segsize = load_count; - if (!buf) { - sg_miter_start(&qh->sg_miter, urb->sg, 1, - SG_MITER_ATOMIC - | SG_MITER_FROM_SG); - if (!sg_miter_next(&qh->sg_miter)) { - dev_err(musb->controller, - "error: sg" - "list empty\n"); - sg_miter_stop(&qh->sg_miter); - goto finish; - } - buf = qh->sg_miter.addr + urb->sg->offset + - urb->actual_length; - load_count = min_t(u32, load_count, - qh->sg_miter.length); - musb_write_fifo(hw_ep, load_count, buf); - qh->sg_miter.consumed = load_count; - sg_miter_stop(&qh->sg_miter); - } else - musb_write_fifo(hw_ep, load_count, buf); + musb_write_fifo(hw_ep, load_count, buf); } -finish: + /* re-enable interrupt */ musb_writew(mbase, MUSB_INTRTXE, int_txe); @@ -892,7 +728,7 @@ finish: if (csr & (MUSB_RXCSR_RXPKTRDY | MUSB_RXCSR_DMAENAB | MUSB_RXCSR_H_REQPKT)) - ERR("broken !rx_reinit, ep%d csr %04x\n", + dev_err(musb->controller, "broken !rx_reinit, ep%d csr %04x\n", hw_ep->epnum, csr); /* scrub any stale state, leaving toggle alone */ @@ -901,31 +737,6 @@ finish: /* kick things off */ - if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { - /* Candidate for DMA */ - dma_channel->actual_len = 0L; - qh->segsize = len; - - /* AUTOREQ is in a DMA register */ - musb_writew(hw_ep->regs, MUSB_RXCSR, csr); - csr = musb_readw(hw_ep->regs, MUSB_RXCSR); - - /* - * Unless caller treats short RX transfers as - * errors, we dare not queue multiple transfers. - */ - dma_ok = dma_controller->channel_program(dma_channel, - packet_sz, !(urb->transfer_flags & - URB_SHORT_NOT_OK), - urb->transfer_dma + offset, - qh->segsize); - if (!dma_ok) { - dma_controller->channel_release(dma_channel); - hw_ep->rx_channel = dma_channel = NULL; - } else - csr |= MUSB_RXCSR_DMAENAB; - } - csr |= MUSB_RXCSR_H_REQPKT; dev_dbg(musb->controller, "RXCSR%d := %04x\n", epnum, csr); musb_writew(hw_ep->regs, MUSB_RXCSR, csr); @@ -939,7 +750,6 @@ finish: static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, int is_in) { - struct dma_channel *dma; struct urb *urb; void __iomem *mbase = musb->mregs; void __iomem *epio = ep->regs; @@ -948,8 +758,6 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, musb_ep_select(mbase, ep->epnum); if (is_in) { - dma = is_dma_capable() ? ep->rx_channel : NULL; - /* clear nak timeout bit */ rx_csr = musb_readw(epio, MUSB_RXCSR); rx_csr |= MUSB_RXCSR_H_WZC_BITS; @@ -958,8 +766,6 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, cur_qh = first_qh(&musb->in_bulk); } else { - dma = is_dma_capable() ? ep->tx_channel : NULL; - /* clear nak timeout bit */ tx_csr = musb_readw(epio, MUSB_TXCSR); tx_csr |= MUSB_TXCSR_H_WZC_BITS; @@ -970,12 +776,6 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, } if (cur_qh) { urb = next_urb(cur_qh); - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - musb->dma_controller->channel_abort(dma); - urb->actual_length += dma->actual_len; - dma->actual_len = 0L; - } musb_save_toggle(cur_qh, is_in, urb); if (is_in) { @@ -1068,7 +868,7 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) } break; default: - ERR("bogus ep0 stage %d\n", musb->ep0_stage); + dev_err(musb->controller, "bogus ep0 stage %d\n", musb->ep0_stage); break; } @@ -1161,7 +961,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) if (unlikely(!urb)) { /* stop endpoint since we have no place for its data, this * SHOULD NEVER HAPPEN! */ - ERR("no URB for end 0\n"); + dev_err(musb->controller, "no URB for end 0\n"); musb_h_ep0_flush_fifo(hw_ep); goto done; @@ -1183,9 +983,6 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) csr = MUSB_CSR0_H_STATUSPKT | MUSB_CSR0_TXPKTRDY; - /* disable ping token in status phase */ - csr |= MUSB_CSR0_H_DIS_PING; - /* flag status stage */ musb->ep0_stage = MUSB_EP0_STATUS; @@ -1204,23 +1001,6 @@ done: return retval; } - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Host side TX (OUT) using Mentor DMA works as follows: - submit_urb -> - - if queue was empty, Program Endpoint - - ... which starts DMA to fifo in mode 1 or 0 - - DMA Isr (transfer complete) -> TxAvail() - - Stop DMA (~DmaEnab) (<--- Alert ... currently happens - only in musb_cleanup_urb) - - TxPktRdy has to be set in mode 0 or for - short packets in mode 1. -*/ - -#endif - /* Service a Tx-Available or dma completion irq for the endpoint */ void musb_host_tx(struct musb *musb, u8 epnum) { @@ -1235,7 +1015,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) struct urb *urb = next_urb(qh); u32 status = 0; void __iomem *mbase = musb->mregs; - struct dma_channel *dma; bool transfer_pending = false; musb_ep_select(mbase, epnum); @@ -1248,9 +1027,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) } pipe = urb->pipe; - dma = is_dma_capable() ? hw_ep->tx_channel : NULL; - dev_dbg(musb->controller, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr, - dma ? ", dma" : ""); + dev_dbg(musb->controller, "OUT/TX%d end, csr %04x\n", epnum, tx_csr); /* check for errors */ if (tx_csr & MUSB_TXCSR_H_RXSTALL) { @@ -1291,13 +1068,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) return; } -done: if (status) { - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - musb->dma_controller->channel_abort(dma); - } - /* do the proper sequence to abort the transfer in the * usb core; the dma engine should already be stopped. */ @@ -1318,95 +1089,11 @@ done: done = true; } - /* second cppi case */ - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr); - return; - } - - if (is_dma_capable() && dma && !status) { - /* - * DMA has completed. But if we're using DMA mode 1 (multi - * packet DMA), we need a terminal TXPKTRDY interrupt before - * we can consider this transfer completed, lest we trash - * its last packet when writing the next URB's data. So we - * switch back to mode 0 to get that interrupt; we'll come - * back here once it happens. - */ - if (tx_csr & MUSB_TXCSR_DMAMODE) { - /* - * We shouldn't clear DMAMODE with DMAENAB set; so - * clear them in a safe order. That should be OK - * once TXPKTRDY has been set (and I've never seen - * it being 0 at this moment -- DMA interrupt latency - * is significant) but if it hasn't been then we have - * no choice but to stop being polite and ignore the - * programmer's guide... :-) - * - * Note that we must write TXCSR with TXPKTRDY cleared - * in order not to re-trigger the packet send (this bit - * can't be cleared by CPU), and there's another caveat: - * TXPKTRDY may be set shortly and then cleared in the - * double-buffered FIFO mode, so we do an extra TXCSR - * read for debouncing... - */ - tx_csr &= musb_readw(epio, MUSB_TXCSR); - if (tx_csr & MUSB_TXCSR_TXPKTRDY) { - tx_csr &= ~(MUSB_TXCSR_DMAENAB | - MUSB_TXCSR_TXPKTRDY); - musb_writew(epio, MUSB_TXCSR, - tx_csr | MUSB_TXCSR_H_WZC_BITS); - } - tx_csr &= ~(MUSB_TXCSR_DMAMODE | - MUSB_TXCSR_TXPKTRDY); - musb_writew(epio, MUSB_TXCSR, - tx_csr | MUSB_TXCSR_H_WZC_BITS); - - /* - * There is no guarantee that we'll get an interrupt - * after clearing DMAMODE as we might have done this - * too late (after TXPKTRDY was cleared by controller). - * Re-read TXCSR as we have spoiled its previous value. - */ - tx_csr = musb_readw(epio, MUSB_TXCSR); - } - - /* - * We may get here from a DMA completion or TXPKTRDY interrupt. - * In any case, we must check the FIFO status here and bail out - * only if the FIFO still has data -- that should prevent the - * "missed" TXPKTRDY interrupts and deal with double-buffered - * FIFO mode too... - */ - if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) { - dev_dbg(musb->controller, "DMA complete but packet still in FIFO, " - "CSR %04x\n", tx_csr); - return; - } - } - - if (!status || dma || usb_pipeisoc(pipe)) { - if (dma) - length = dma->actual_len; - else - length = qh->segsize; + if (!status) { + length = qh->segsize; qh->offset += length; - if (usb_pipeisoc(pipe)) { - struct usb_iso_packet_descriptor *d; - - d = urb->iso_frame_desc + qh->iso_idx; - d->actual_length = length; - d->status = status; - if (++qh->iso_idx >= urb->number_of_packets) { - done = true; - } else { - d++; - offset = d->offset; - length = d->length; - } - } else if (dma && urb->transfer_buffer_length == qh->offset) { - done = true; + if (0) { } else { /* see if we need to send more data, or ZLP */ if (qh->segsize < qh->maxpacket) @@ -1438,13 +1125,6 @@ done: urb->actual_length = qh->offset; musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT); return; - } else if ((usb_pipeisoc(pipe) || transfer_pending) && dma) { - if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb, - offset, length)) { - if (is_cppi_enabled() || tusb_dma_omap()) - musb_h_tx_dma_start(hw_ep); - return; - } } else if (tx_csr & MUSB_TXCSR_DMAENAB) { dev_dbg(musb->controller, "not complete, but DMA enabled?\n"); return; @@ -1459,85 +1139,16 @@ done: */ if (length > qh->maxpacket) length = qh->maxpacket; - /* Unmap the buffer so that CPU can use it */ - usb_hcd_unmap_urb_for_dma(musb->hcd, urb); - /* - * We need to map sg if the transfer_buffer is - * NULL. - */ - if (!urb->transfer_buffer) - qh->use_sg = true; - - if (qh->use_sg) { - /* sg_miter_start is already done in musb_ep_program */ - if (!sg_miter_next(&qh->sg_miter)) { - dev_err(musb->controller, "error: sg list empty\n"); - sg_miter_stop(&qh->sg_miter); - status = -EINVAL; - goto done; - } - urb->transfer_buffer = qh->sg_miter.addr; - length = min_t(u32, length, qh->sg_miter.length); - musb_write_fifo(hw_ep, length, urb->transfer_buffer); - qh->sg_miter.consumed = length; - sg_miter_stop(&qh->sg_miter); - } else { - musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); - } + musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); qh->segsize = length; - if (qh->use_sg) { - if (offset + length >= urb->transfer_buffer_length) - qh->use_sg = false; - } - musb_ep_select(mbase, epnum); musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); } - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Host side RX (IN) using Mentor DMA works as follows: - submit_urb -> - - if queue was empty, ProgramEndpoint - - first IN token is sent out (by setting ReqPkt) - LinuxIsr -> RxReady() - /\ => first packet is received - | - Set in mode 0 (DmaEnab, ~ReqPkt) - | -> DMA Isr (transfer complete) -> RxReady() - | - Ack receive (~RxPktRdy), turn off DMA (~DmaEnab) - | - if urb not complete, send next IN token (ReqPkt) - | | else complete urb. - | | - --------------------------- - * - * Nuances of mode 1: - * For short packets, no ack (+RxPktRdy) is sent automatically - * (even if AutoClear is ON) - * For full packets, ack (~RxPktRdy) and next IN token (+ReqPkt) is sent - * automatically => major problem, as collecting the next packet becomes - * difficult. Hence mode 1 is not used. - * - * REVISIT - * All we care about at this driver level is that - * (a) all URBs terminate with REQPKT cleared and fifo(s) empty; - * (b) termination conditions are: short RX, or buffer full; - * (c) fault modes include - * - iff URB_SHORT_NOT_OK, short RX status is -EREMOTEIO. - * (and that endpoint's dma queue stops immediately) - * - overflow (full, PLUS more bytes in the terminal packet) - * - * So for example, usb-storage sets URB_SHORT_NOT_OK, and would - * thus be a great candidate for using mode 1 ... for all but the - * last packet of one URB's transfer. - */ - -#endif - /* * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso, * and high-bandwidth IN transfer cases. @@ -1555,13 +1166,10 @@ void musb_host_rx(struct musb *musb, u8 epnum) bool iso_err = false; bool done = false; u32 status; - struct dma_channel *dma; - unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG; musb_ep_select(mbase, epnum); urb = next_urb(qh); - dma = is_dma_capable() ? hw_ep->rx_channel : NULL; status = 0; xfer_len = 0; @@ -1582,8 +1190,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) pipe = urb->pipe; dev_dbg(musb->controller, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n", - epnum, rx_csr, urb->actual_length, - dma ? dma->actual_len : 0); + epnum, rx_csr, urb->actual_length, 0); /* check for errors, concurrent stall & unlink is not really * handled yet! */ @@ -1637,129 +1244,32 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* faults abort the transfer */ if (status) { - /* clean up dma and collect transfer count */ - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - musb->dma_controller->channel_abort(dma); - xfer_len = dma->actual_len; - } musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG); musb_writeb(epio, MUSB_RXINTERVAL, 0); done = true; goto finish; } - if (unlikely(dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY)) { - /* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */ - ERR("RX%d dma busy, csr %04x\n", epnum, rx_csr); - goto finish; - } - /* thorough shutdown for now ... given more precise fault handling * and better queueing support, we might keep a DMA pipeline going * while processing this irq for earlier completions. */ - /* FIXME this is _way_ too much in-line logic for Mentor DMA */ - -#if !defined(CONFIG_USB_INVENTRA_DMA) && !defined(CONFIG_USB_UX500_DMA) if (rx_csr & MUSB_RXCSR_H_REQPKT) { - /* REVISIT this happened for a while on some short reads... - * the cleanup still needs investigation... looks bad... - * and also duplicates dma cleanup code above ... plus, - * shouldn't this be the "half full" double buffer case? - */ - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - musb->dma_controller->channel_abort(dma); - xfer_len = dma->actual_len; - done = true; - } - dev_dbg(musb->controller, "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr, - xfer_len, dma ? ", dma" : ""); + xfer_len, ""); rx_csr &= ~MUSB_RXCSR_H_REQPKT; musb_ep_select(mbase, epnum); musb_writew(epio, MUSB_RXCSR, MUSB_RXCSR_H_WZC_BITS | rx_csr); } -#endif - if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) { - xfer_len = dma->actual_len; - - val &= ~(MUSB_RXCSR_DMAENAB - | MUSB_RXCSR_H_AUTOREQ - | MUSB_RXCSR_AUTOCLEAR - | MUSB_RXCSR_RXPKTRDY); - musb_writew(hw_ep->regs, MUSB_RXCSR, val); - -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ - defined(CONFIG_USB_TI_CPPI41_DMA) - if (usb_pipeisoc(pipe)) { - struct usb_iso_packet_descriptor *d; - d = urb->iso_frame_desc + qh->iso_idx; - d->actual_length = xfer_len; - - /* even if there was an error, we did the dma - * for iso_frame_desc->length - */ - if (d->status != -EILSEQ && d->status != -EOVERFLOW) - d->status = 0; - - if (++qh->iso_idx >= urb->number_of_packets) { - done = true; - } else { -#if defined(CONFIG_USB_TI_CPPI41_DMA) - struct dma_controller *c; - dma_addr_t *buf; - u32 length, ret; - - c = musb->dma_controller; - buf = (void *) - urb->iso_frame_desc[qh->iso_idx].offset - + (u32)urb->transfer_dma; - - length = - urb->iso_frame_desc[qh->iso_idx].length; - - val |= MUSB_RXCSR_DMAENAB; - musb_writew(hw_ep->regs, MUSB_RXCSR, val); - - ret = c->channel_program(dma, qh->maxpacket, - 0, (u32) buf, length); -#endif - done = false; - } - - } else { - /* done if urb buffer is full or short packet is recd */ - done = (urb->actual_length + xfer_len >= - urb->transfer_buffer_length - || dma->actual_len < qh->maxpacket - || dma->rx_packet_done); - } - - /* send IN token for next packet, without AUTOREQ */ - if (!done) { - val |= MUSB_RXCSR_H_REQPKT; - musb_writew(epio, MUSB_RXCSR, - MUSB_RXCSR_H_WZC_BITS | val); - } - - dev_dbg(musb->controller, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum, - done ? "off" : "reset", - musb_readw(epio, MUSB_RXCSR), - musb_readw(epio, MUSB_RXCOUNT)); -#else - done = true; -#endif - } else if (urb->status == -EINPROGRESS) { + if (urb->status == -EINPROGRESS) { /* if no errors, be sure a packet is ready for unloading */ if (unlikely(!(rx_csr & MUSB_RXCSR_RXPKTRDY))) { status = -EPROTO; - ERR("Rx interrupt with no errors or packet!\n"); + dev_err(musb->controller, "Rx interrupt with no errors or packet!\n"); /* FIXME this is another "SHOULD NEVER HAPPEN" */ @@ -1772,165 +1282,10 @@ void musb_host_rx(struct musb *musb, u8 epnum) } /* we are expecting IN packets */ -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ - defined(CONFIG_USB_TI_CPPI41_DMA) - if (dma) { - struct dma_controller *c; - u16 rx_count; - int ret, length; - dma_addr_t buf; - - rx_count = musb_readw(epio, MUSB_RXCOUNT); - - dev_dbg(musb->controller, "RX%d count %d, buffer 0x%llx len %d/%d\n", - epnum, rx_count, - (unsigned long long) urb->transfer_dma - + urb->actual_length, - qh->offset, - urb->transfer_buffer_length); - - c = musb->dma_controller; - - if (usb_pipeisoc(pipe)) { - int d_status = 0; - struct usb_iso_packet_descriptor *d; - - d = urb->iso_frame_desc + qh->iso_idx; - - if (iso_err) { - d_status = -EILSEQ; - urb->error_count++; - } - if (rx_count > d->length) { - if (d_status == 0) { - d_status = -EOVERFLOW; - urb->error_count++; - } - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n",\ - rx_count, d->length); - - length = d->length; - } else - length = rx_count; - d->status = d_status; - buf = urb->transfer_dma + d->offset; - } else { - length = rx_count; - buf = urb->transfer_dma + - urb->actual_length; - } - - dma->desired_mode = 0; -#ifdef USE_MODE1 - /* because of the issue below, mode 1 will - * only rarely behave with correct semantics. - */ - if ((urb->transfer_flags & - URB_SHORT_NOT_OK) - && (urb->transfer_buffer_length - - urb->actual_length) - > qh->maxpacket) - dma->desired_mode = 1; - if (rx_count < hw_ep->max_packet_sz_rx) { - length = rx_count; - dma->desired_mode = 0; - } else { - length = urb->transfer_buffer_length; - } -#endif - -/* Disadvantage of using mode 1: - * It's basically usable only for mass storage class; essentially all - * other protocols also terminate transfers on short packets. - * - * Details: - * An extra IN token is sent at the end of the transfer (due to AUTOREQ) - * If you try to use mode 1 for (transfer_buffer_length - 512), and try - * to use the extra IN token to grab the last packet using mode 0, then - * the problem is that you cannot be sure when the device will send the - * last packet and RxPktRdy set. Sometimes the packet is recd too soon - * such that it gets lost when RxCSR is re-set at the end of the mode 1 - * transfer, while sometimes it is recd just a little late so that if you - * try to configure for mode 0 soon after the mode 1 transfer is - * completed, you will find rxcount 0. Okay, so you might think why not - * wait for an interrupt when the pkt is recd. Well, you won't get any! - */ - - val = musb_readw(epio, MUSB_RXCSR); - val &= ~MUSB_RXCSR_H_REQPKT; - - if (dma->desired_mode == 0) - val &= ~MUSB_RXCSR_H_AUTOREQ; - else - val |= MUSB_RXCSR_H_AUTOREQ; - val |= MUSB_RXCSR_DMAENAB; - - /* autoclear shouldn't be set in high bandwidth */ - if (qh->hb_mult == 1) - val |= MUSB_RXCSR_AUTOCLEAR; + if (1) { + done = musb_host_packet_rx(musb, urb, + epnum, iso_err); - musb_writew(epio, MUSB_RXCSR, - MUSB_RXCSR_H_WZC_BITS | val); - - /* REVISIT if when actual_length != 0, - * transfer_buffer_length needs to be - * adjusted first... - */ - ret = c->channel_program( - dma, qh->maxpacket, - dma->desired_mode, buf, length); - - if (!ret) { - c->channel_release(dma); - hw_ep->rx_channel = NULL; - dma = NULL; - val = musb_readw(epio, MUSB_RXCSR); - val &= ~(MUSB_RXCSR_DMAENAB - | MUSB_RXCSR_H_AUTOREQ - | MUSB_RXCSR_AUTOCLEAR); - musb_writew(epio, MUSB_RXCSR, val); - } - } -#endif /* Mentor DMA */ - - if (!dma) { - unsigned int received_len; - - /* Unmap the buffer so that CPU can use it */ - usb_hcd_unmap_urb_for_dma(musb->hcd, urb); - - /* - * We need to map sg if the transfer_buffer is - * NULL. - */ - if (!urb->transfer_buffer) { - qh->use_sg = true; - sg_miter_start(&qh->sg_miter, urb->sg, 1, - sg_flags); - } - - if (qh->use_sg) { - if (!sg_miter_next(&qh->sg_miter)) { - dev_err(musb->controller, "error: sg list empty\n"); - sg_miter_stop(&qh->sg_miter); - status = -EINVAL; - done = true; - goto finish; - } - urb->transfer_buffer = qh->sg_miter.addr; - received_len = urb->actual_length; - qh->offset = 0x0; - done = musb_host_packet_rx(musb, urb, epnum, - iso_err); - /* Calculate the number of bytes received */ - received_len = urb->actual_length - - received_len; - qh->sg_miter.consumed = received_len; - sg_miter_stop(&qh->sg_miter); - } else { - done = musb_host_packet_rx(musb, urb, - epnum, iso_err); - } dev_dbg(musb->controller, "read %spacket\n", done ? "last " : ""); } } @@ -1939,8 +1294,6 @@ finish: urb->actual_length += xfer_len; qh->offset += xfer_len; if (done) { - if (qh->use_sg) - qh->use_sg = false; if (urb->status == -EINPROGRESS) urb->status = status; @@ -1958,7 +1311,7 @@ static int musb_schedule( struct musb_qh *qh, int is_in) { - int idle = 0; + int idle; int best_diff; int best_end, epnum; struct musb_hw_ep *hw_ep = NULL; @@ -2038,7 +1391,7 @@ static int musb_schedule( head = &musb->out_bulk; /* Enable bulk RX/TX NAK timeout scheme when bulk requests are - * multiplexed. This scheme does not work in high speed to full + * multiplexed. This scheme doen't work in high speed to full * speed scenario as NAK interrupts are not coming from a * full speed device connected to a high speed device. * NAK timeout interval is 8 (128 uframe or 16ms) for HS and @@ -2069,7 +1422,17 @@ success: return 0; } -static int musb_urb_enqueue( + +/* check if transaction translator is needed for device */ +static int tt_needed(struct musb *musb, struct usb_device *dev) +{ + if ((musb_readb(musb->mregs, MUSB_POWER) & MUSB_POWER_HSMODE) && + (dev->speed < USB_SPEED_HIGH)) + return 1; + return 0; +} + +int musb_urb_enqueue( struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) @@ -2082,7 +1445,6 @@ static int musb_urb_enqueue( int ret; unsigned type_reg; unsigned interval; - /* host role must be active */ if (!is_host_active(musb) || !musb->is_active) return -ENODEV; @@ -2203,17 +1565,13 @@ static int musb_urb_enqueue( if (musb->is_multipoint) { struct usb_device *parent = urb->dev->parent; - if (parent != hcd->self.root_hub) { + if (parent) { qh->h_addr_reg = (u8) parent->devnum; - /* set up tt info if needed */ - if (urb->dev->tt) { - qh->h_port_reg = (u8) urb->dev->ttport; - if (urb->dev->tt->hub) - qh->h_addr_reg = - (u8) urb->dev->tt->hub->devnum; - if (urb->dev->tt->multi) - qh->h_addr_reg |= 0x80; + if (tt_needed(musb, urb->dev)) { + u16 hub_port = find_tt(urb->dev); + qh->h_addr_reg = (u8) (hub_port >> 8); + qh->h_port_reg = (u8) (hub_port & 0xff); } } } @@ -2252,16 +1610,14 @@ done: return ret; } - /* * abort a transfer that's at the head of a hardware queue. * called with controller locked, irqs blocked * that hardware queue advances to the next transfer, unless prevented */ -static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) +static noinline int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) { struct musb_hw_ep *ep = qh->hw_ep; - struct musb *musb = ep->musb; void __iomem *epio = ep->regs; unsigned hw_end = ep->epnum; void __iomem *regs = ep->musb->mregs; @@ -2271,20 +1627,6 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) musb_ep_select(regs, hw_end); - if (is_dma_capable()) { - struct dma_channel *dma; - - dma = is_in ? ep->rx_channel : ep->tx_channel; - if (dma) { - status = ep->musb->dma_controller->channel_abort(dma); - dev_dbg(musb->controller, - "abort %cX%d DMA for urb %p --> %d\n", - is_in ? 'R' : 'T', ep->epnum, - urb, status); - urb->actual_length += dma->actual_len; - } - } - /* turn off DMA requests, discard state, stop polling ... */ if (ep->epnum && is_in) { /* giveback saves bulk toggle */ @@ -2316,13 +1658,13 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) return status; } -static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { struct musb *musb = hcd_to_musb(hcd); struct musb_qh *qh; unsigned long flags; int is_in = usb_pipein(urb->pipe); - int ret; + int ret = 0; dev_dbg(musb->controller, "urb=%p, dev%d ep%d%s\n", urb, usb_pipedevice(urb->pipe), @@ -2330,9 +1672,6 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) is_in ? "in" : "out"); spin_lock_irqsave(&musb->lock, flags); - ret = usb_hcd_check_unlink_urb(hcd, urb, status); - if (ret) - goto done; qh = urb->hcpriv; if (!qh) @@ -2374,335 +1713,37 @@ done: return ret; } -/* disable an endpoint */ -static void -musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) -{ - u8 is_in = hep->desc.bEndpointAddress & USB_DIR_IN; - unsigned long flags; - struct musb *musb = hcd_to_musb(hcd); - struct musb_qh *qh; - struct urb *urb; - - spin_lock_irqsave(&musb->lock, flags); - - qh = hep->hcpriv; - if (qh == NULL) - goto exit; - - /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */ - - /* Kick the first URB off the hardware, if needed */ - qh->is_ready = 0; - if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) { - urb = next_urb(qh); - - /* make software (then hardware) stop ASAP */ - if (!urb->unlinked) - urb->status = -ESHUTDOWN; - - /* cleanup */ - musb_cleanup_urb(urb, qh); - - /* Then nuke all the others ... and advance the - * queue on hw_ep (e.g. bulk ring) when we're done. - */ - while (!list_empty(&hep->urb_list)) { - urb = next_urb(qh); - urb->status = -ESHUTDOWN; - musb_advance_schedule(musb, urb, qh->hw_ep, is_in); - } - } else { - /* Just empty the queue; the hardware is busy with - * other transfers, and since !qh->is_ready nothing - * will activate any of these as it advances. - */ - while (!list_empty(&hep->urb_list)) - musb_giveback(musb, next_urb(qh), -ESHUTDOWN); - - hep->hcpriv = NULL; - list_del(&qh->ring); - kfree(qh); - } -exit: - spin_unlock_irqrestore(&musb->lock, flags); -} - -static int musb_h_get_frame_number(struct usb_hcd *hcd) -{ - struct musb *musb = hcd_to_musb(hcd); - - return musb_readw(musb->mregs, MUSB_FRAME); -} - -static int musb_h_start(struct usb_hcd *hcd) -{ - struct musb *musb = hcd_to_musb(hcd); - - /* NOTE: musb_start() is called when the hub driver turns - * on port power, or when (OTG) peripheral starts. - */ - hcd->state = HC_STATE_RUNNING; - musb->port1_status = 0; - return 0; -} - -static void musb_h_stop(struct usb_hcd *hcd) -{ - musb_stop(hcd_to_musb(hcd)); - hcd->state = HC_STATE_HALT; -} - -static int musb_bus_suspend(struct usb_hcd *hcd) -{ - struct musb *musb = hcd_to_musb(hcd); - u8 devctl; - - musb_port_suspend(musb, true); - - if (!is_host_active(musb)) - return 0; - - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - return 0; - case OTG_STATE_A_WAIT_VRISE: - /* ID could be grounded even if there's no device - * on the other end of the cable. NOTE that the - * A_WAIT_VRISE timers are messy with MUSB... - */ - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; - break; - default: - break; - } - - if (musb->is_active) { - WARNING("trying to suspend as %s while active\n", - usb_otg_state_string(musb->xceiv->state)); - return -EBUSY; - } else - return 0; -} - -static int musb_bus_resume(struct usb_hcd *hcd) -{ - struct musb *musb = hcd_to_musb(hcd); - - if (musb->config && - musb->config->host_port_deassert_reset_at_resume) - musb_port_reset(musb, false); - - return 0; -} - -#ifndef CONFIG_MUSB_PIO_ONLY - -#define MUSB_USB_DMA_ALIGN 4 - -struct musb_temp_buffer { - void *kmalloc_ptr; - void *old_xfer_buffer; - u8 data[0]; -}; - -static void musb_free_temp_buffer(struct urb *urb) -{ - enum dma_data_direction dir; - struct musb_temp_buffer *temp; - - if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) - return; - - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - temp = container_of(urb->transfer_buffer, struct musb_temp_buffer, - data); - - if (dir == DMA_FROM_DEVICE) { - memcpy(temp->old_xfer_buffer, temp->data, - urb->transfer_buffer_length); - } - urb->transfer_buffer = temp->old_xfer_buffer; - kfree(temp->kmalloc_ptr); - - urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; -} - -static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) -{ - enum dma_data_direction dir; - struct musb_temp_buffer *temp; - void *kmalloc_ptr; - size_t kmalloc_size; - - if (urb->num_sgs || urb->sg || - urb->transfer_buffer_length == 0 || - !((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1))) - return 0; - - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - /* Allocate a buffer with enough padding for alignment */ - kmalloc_size = urb->transfer_buffer_length + - sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1; - - kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); - if (!kmalloc_ptr) - return -ENOMEM; - - /* Position our struct temp_buffer such that data is aligned */ - temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN); - - - temp->kmalloc_ptr = kmalloc_ptr; - temp->old_xfer_buffer = urb->transfer_buffer; - if (dir == DMA_TO_DEVICE) - memcpy(temp->data, urb->transfer_buffer, - urb->transfer_buffer_length); - urb->transfer_buffer = temp->data; - - urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; - - return 0; -} - -static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct musb *musb = hcd_to_musb(hcd); - int ret; - - /* - * The DMA engine in RTL1.8 and above cannot handle - * DMA addresses that are not aligned to a 4 byte boundary. - * For such engine implemented (un)map_urb_for_dma hooks. - * Do not use these hooks for RTL<1.8 - */ - if (musb->hwvers < MUSB_HWVERS_1800) - return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); - - ret = musb_alloc_temp_buffer(urb, mem_flags); - if (ret) - return ret; - - ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); - if (ret) - musb_free_temp_buffer(urb); - - return ret; -} - -static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) -{ - struct musb *musb = hcd_to_musb(hcd); - - usb_hcd_unmap_urb_for_dma(hcd, urb); - - /* Do not use this hook for RTL<1.8 (see description above) */ - if (musb->hwvers < MUSB_HWVERS_1800) - return; - - musb_free_temp_buffer(urb); -} -#endif /* !CONFIG_MUSB_PIO_ONLY */ - -static const struct hc_driver musb_hc_driver = { - .description = "musb-hcd", - .product_desc = "MUSB HDRC host driver", - .hcd_priv_size = sizeof(struct musb *), - .flags = HCD_USB2 | HCD_MEMORY, - - /* not using irq handler or reset hooks from usbcore, since - * those must be shared with peripheral code for OTG configs - */ - - .start = musb_h_start, - .stop = musb_h_stop, - - .get_frame_number = musb_h_get_frame_number, - - .urb_enqueue = musb_urb_enqueue, - .urb_dequeue = musb_urb_dequeue, - .endpoint_disable = musb_h_disable, - -#ifndef CONFIG_MUSB_PIO_ONLY - .map_urb_for_dma = musb_map_urb_for_dma, - .unmap_urb_for_dma = musb_unmap_urb_for_dma, -#endif - - .hub_status_data = musb_hub_status_data, - .hub_control = musb_hub_control, - .bus_suspend = musb_bus_suspend, - .bus_resume = musb_bus_resume, - /* .start_port_reset = NULL, */ - /* .hub_irq_enable = NULL, */ -}; - int musb_host_alloc(struct musb *musb) { - struct device *dev = musb->controller; - /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ - musb->hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); + musb->hcd = xzalloc(sizeof(struct usb_hcd)); if (!musb->hcd) return -EINVAL; - *musb->hcd->hcd_priv = (unsigned long) musb; - musb->hcd->self.uses_pio_for_control = 1; - musb->hcd->uses_new_polling = 1; - musb->hcd->has_tt = 1; + musb->hcd->hcd_priv = musb; return 0; } -void musb_host_cleanup(struct musb *musb) -{ - if (musb->port_mode == MUSB_PORT_MODE_GADGET) - return; - usb_remove_hcd(musb->hcd); - musb->hcd = NULL; -} - void musb_host_free(struct musb *musb) { - usb_put_hcd(musb->hcd); } int musb_host_setup(struct musb *musb, int power_budget) { - int ret; struct usb_hcd *hcd = musb->hcd; MUSB_HST_MODE(musb); - musb->xceiv->otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_IDLE; - otg_set_host(musb->xceiv->otg, &hcd->self); hcd->self.otg_port = 1; - musb->xceiv->otg->host = &hcd->self; - hcd->power_budget = 2 * (power_budget ? : 250); - ret = usb_add_hcd(hcd, 0, 0); - if (ret < 0) - return ret; - - device_wakeup_enable(hcd->self.controller); return 0; } void musb_host_resume_root_hub(struct musb *musb) { - usb_hcd_resume_root_hub(musb->hcd); } void musb_host_poke_root_hub(struct musb *musb) { - MUSB_HST_MODE(musb); - if (musb->hcd->status_urb) - usb_hcd_poll_rh_status(musb->hcd); - else - usb_hcd_resume_root_hub(musb->hcd); } diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 7bbf01bf4b..0937808de8 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -35,7 +35,78 @@ #ifndef _MUSB_HOST_H #define _MUSB_HOST_H -#include <linux/scatterlist.h> +//#include <linux/scatterlist.h> +#include <linux/list.h> +#include <usb/usb.h> +#include <asm/unaligned.h> + +/* + * 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 */ + +#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) + +struct ep_device; +struct urb; + +typedef void (*usb_complete_t)(struct urb *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) */ + int error_count; /* (return) number of ISO errors */ + usb_complete_t complete; /* (in) completion routine */ +}; + +#define USB_DT_SS_EP_COMP_SIZE 6 + +/** + * struct usb_host_endpoint - host-side endpoint descriptor and queue + * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder + * @ss_ep_comp: SuperSpeed companion descriptor for this endpoint + * @urb_list: urbs queued to this endpoint; maintained by usbcore + * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH) + * with one or more transfer descriptors (TDs) per urb + * @ep_dev: ep_device for sysfs info + * @extra: descriptors following this endpoint in the configuration + * @extralen: how many bytes of "extra" are valid + * @enabled: URBs may be submitted to this endpoint + * + * USB requests are always queued to a given endpoint, identified by a + * descriptor within an active interface in a given USB configuration. + */ +struct usb_host_endpoint { + struct usb_endpoint_descriptor desc; + struct usb_ss_ep_comp_descriptor ss_ep_comp; + struct list_head urb_list; + void *hcpriv; + //struct ep_device *ep_dev; /* For sysfs info */ + + unsigned char *extra; /* Extra descriptors */ + int extralen; + int enabled; +}; /* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */ struct musb_qh { @@ -63,8 +134,8 @@ struct musb_qh { u16 maxpacket; u16 frame; /* for periodic schedule */ unsigned iso_idx; /* in urb->iso_frame_desc[] */ - struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */ - bool use_sg; /* to track urb using sglist */ + //struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */ + //bool use_sg; /* to track urb using sglist */ }; /* map from control or bulk queue head to the first qh on that ring */ @@ -75,26 +146,21 @@ static inline struct musb_qh *first_qh(struct list_head *q) return list_entry(q->next, struct musb_qh, ring); } +struct usb_hcd; -#if IS_ENABLED(CONFIG_USB_MUSB_HOST) || IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE) +#if IS_ENABLED(CONFIG_USB_MUSB_HOST) extern struct musb *hcd_to_musb(struct usb_hcd *); extern irqreturn_t musb_h_ep0_irq(struct musb *); extern int musb_host_alloc(struct musb *); extern int musb_host_setup(struct musb *, int); -extern void musb_host_cleanup(struct musb *); -extern void musb_host_tx(struct musb *, u8); -extern void musb_host_rx(struct musb *, u8); extern void musb_root_disconnect(struct musb *musb); extern void musb_host_free(struct musb *); extern void musb_host_cleanup(struct musb *); extern void musb_host_tx(struct musb *, u8); extern void musb_host_rx(struct musb *, u8); -extern void musb_root_disconnect(struct musb *musb); extern void musb_host_resume_root_hub(struct musb *musb); extern void musb_host_poke_root_hub(struct musb *musb); -extern void musb_port_suspend(struct musb *musb, bool do_suspend); extern void musb_port_reset(struct musb *musb, bool do_reset); -extern void musb_host_finish_resume(struct work_struct *work); #else static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) { @@ -124,9 +190,7 @@ static inline void musb_root_disconnect(struct musb *musb) {} static inline void musb_host_resume_root_hub(struct musb *musb) {} static inline void musb_host_poll_rh_status(struct musb *musb) {} static inline void musb_host_poke_root_hub(struct musb *musb) {} -static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} static inline void musb_port_reset(struct musb *musb, bool do_reset) {} -static inline void musb_host_finish_resume(struct work_struct *work) {} #endif struct usb_hcd; @@ -148,4 +212,47 @@ static inline struct urb *next_urb(struct musb_qh *qh) return list_entry(queue->next, struct urb, urb_list); } +/* + * Endpoints + */ +#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ + +static inline u16 find_tt(struct usb_device *dev) +{ + u8 chid; + u8 hub; + + /* Find out the nearest parent which is high speed */ + while (dev->parent->parent != NULL) + if (dev->parent->speed != USB_SPEED_HIGH) + dev = dev->parent; + else + break; + + /* determine the port address at that hub */ + hub = dev->parent->devnum; + for (chid = 0; chid < USB_MAXCHILDREN; chid++) + if (dev->parent->children[chid] == dev) + break; + + return (hub << 8) | chid; +} + +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); + +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); +} + #endif /* _MUSB_HOST_H */ diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index eebeed78ed..a4be339355 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -35,7 +35,7 @@ #ifndef __MUSB_LINUX_PLATFORM_ARCH_H__ #define __MUSB_LINUX_PLATFORM_ARCH_H__ -#include <linux/io.h> +#include <io.h> #ifndef CONFIG_BLACKFIN diff --git a/drivers/usb/musb/phy-am335x-control.c b/drivers/usb/musb/phy-am335x-control.c new file mode 100644 index 0000000000..a241c84fed --- /dev/null +++ b/drivers/usb/musb/phy-am335x-control.c @@ -0,0 +1,168 @@ +#include <common.h> +#include <init.h> +#include <io.h> +#include <linux/err.h> + +struct phy_control { + void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); + void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); +}; + +struct am335x_control_usb { + struct device_d *dev; + void __iomem *phy_reg; + void __iomem *wkup; + spinlock_t lock; + struct phy_control phy_ctrl; +}; + +#define AM335X_USB0_CTRL 0x0 +#define AM335X_USB1_CTRL 0x8 +#define AM335x_USB_WKUP 0x0 + +#define USBPHY_CM_PWRDN (1 << 0) +#define USBPHY_OTG_PWRDN (1 << 1) +#define USBPHY_OTGVDET_EN (1 << 19) +#define USBPHY_OTGSESSEND_EN (1 << 20) + +#define AM335X_PHY0_WK_EN (1 << 0) +#define AM335X_PHY1_WK_EN (1 << 8) + +static void am335x_phy_wkup(struct phy_control *phy_ctrl, u32 id, bool on) +{ + struct am335x_control_usb *usb_ctrl; + u32 val; + u32 reg; + + usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl); + + switch (id) { + case 0: + reg = AM335X_PHY0_WK_EN; + break; + case 1: + reg = AM335X_PHY1_WK_EN; + break; + default: + WARN_ON(1); + return; + } + + spin_lock(&usb_ctrl->lock); + val = readl(usb_ctrl->wkup); + + if (on) + val |= reg; + else + val &= ~reg; + + writel(val, usb_ctrl->wkup); + spin_unlock(&usb_ctrl->lock); +} + +static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) +{ + struct am335x_control_usb *usb_ctrl; + u32 val; + u32 reg; + + usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl); + + switch (id) { + case 0: + reg = AM335X_USB0_CTRL; + break; + case 1: + reg = AM335X_USB1_CTRL; + break; + default: + WARN_ON(1); + return; + } + + val = readl(usb_ctrl->phy_reg + reg); + if (on) { + val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); + val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; + } else { + val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; + } + + writel(val, usb_ctrl->phy_reg + reg); +} + +static const struct phy_control ctrl_am335x = { + .phy_power = am335x_phy_power, + .phy_wkup = am335x_phy_wkup, +}; + +static __maybe_unused struct of_device_id omap_control_usb_dt_ids[] = { + { + .compatible = "ti,am335x-usb-ctrl-module", .data = (unsigned long)&ctrl_am335x + }, { + /* sentinel */ + }, +}; + +struct phy_control *am335x_get_phy_control(struct device_d *dev) +{ + struct device_node *node; + struct am335x_control_usb *ctrl_usb; + + node = of_parse_phandle(dev->device_node, "ti,ctrl_mod", 0); + if (!node) + return NULL; + + dev = of_find_device_by_node(node); + if (!dev) + return NULL; + + ctrl_usb = dev->priv; + if (!ctrl_usb) + return NULL; + + return &ctrl_usb->phy_ctrl; +} +EXPORT_SYMBOL(am335x_get_phy_control); + + +static int am335x_control_usb_probe(struct device_d *dev) +{ + /*struct resource *res;*/ + struct am335x_control_usb *ctrl_usb; + const struct phy_control *phy_ctrl; + int ret; + + ret = dev_get_drvdata(dev, (unsigned long *)&phy_ctrl); + if (ret) + return ret; + + ctrl_usb = xzalloc(sizeof(*ctrl_usb)); + if (!ctrl_usb) { + dev_err(dev, "unable to alloc memory for control usb\n"); + return -ENOMEM; + } + + ctrl_usb->dev = dev; + + ctrl_usb->phy_reg = dev_request_mem_region(dev, 0); + if (IS_ERR(ctrl_usb->phy_reg)) + return PTR_ERR(ctrl_usb->phy_reg); + + ctrl_usb->wkup = dev_request_mem_region(dev, 1); + if (IS_ERR(ctrl_usb->wkup)) + return PTR_ERR(ctrl_usb->wkup); + + spin_lock_init(&ctrl_usb->lock); + ctrl_usb->phy_ctrl = *phy_ctrl; + + dev->priv = ctrl_usb; + return 0; +}; + +static struct driver_d am335x_control_driver = { + .name = "am335x-control-usb", + .probe = am335x_control_usb_probe, + .of_compatible = DRV_OF_COMPAT(omap_control_usb_dt_ids), +}; +device_platform_driver(am335x_control_driver); diff --git a/drivers/usb/musb/phy-am335x.c b/drivers/usb/musb/phy-am335x.c new file mode 100644 index 0000000000..2d58bbedb4 --- /dev/null +++ b/drivers/usb/musb/phy-am335x.c @@ -0,0 +1,86 @@ +#include <common.h> +#include <init.h> +#include <io.h> +#include <malloc.h> +#include <linux/err.h> +#include "am35x-phy-control.h" +#include "musb_core.h" + +struct am335x_usbphy { + void __iomem *base; + struct phy_control *phy_ctrl; + int id; + struct usb_phy phy; +}; + +static struct am335x_usbphy *am_usbphy; + +struct usb_phy *am335x_get_usb_phy(void) +{ + return &am_usbphy->phy; +} + +static int am335x_init(struct usb_phy *phy) +{ + struct am335x_usbphy *am_usbphy = container_of(phy, struct am335x_usbphy, phy); + + phy_ctrl_power(am_usbphy->phy_ctrl, am_usbphy->id, true); + return 0; +} + +static int am335x_phy_probe(struct device_d *dev) +{ + int ret; + + am_usbphy = xzalloc(sizeof(*am_usbphy)); + if (!am_usbphy) + return -ENOMEM; + + am_usbphy->base = dev_request_mem_region(dev, 0); + if (!am_usbphy->base) { + ret = -ENODEV; + goto err_free; + } + + am_usbphy->phy_ctrl = am335x_get_phy_control(dev); + if (!am_usbphy->phy_ctrl) + return -ENODEV; + + am_usbphy->id = of_alias_get_id(dev->device_node, "phy"); + if (am_usbphy->id < 0) { + dev_err(dev, "Missing PHY id: %d\n", am_usbphy->id); + return am_usbphy->id; + } + + am_usbphy->phy.init = am335x_init; + dev->priv = am_usbphy; + + dev_info(dev, "am_usbphy %p enabled\n", &am_usbphy->phy); + + return 0; + +err_free: + free(am_usbphy); + + return ret; +}; + +static __maybe_unused struct of_device_id am335x_phy_dt_ids[] = { + { + .compatible = "ti,am335x-usb-phy", + }, { + /* sentinel */ + }, +}; + +static struct driver_d am335x_phy_driver = { + .name = "am335x-phy-driver", + .probe = am335x_phy_probe, + .of_compatible = DRV_OF_COMPAT(am335x_phy_dt_ids), +}; + +static int am335x_phy_init(void) +{ + return platform_driver_register(&am335x_phy_driver); +} +fs_initcall(am335x_phy_init); diff --git a/drivers/usb/musb/phy-am335x.h b/drivers/usb/musb/phy-am335x.h new file mode 100644 index 0000000000..27da2e3b10 --- /dev/null +++ b/drivers/usb/musb/phy-am335x.h @@ -0,0 +1,6 @@ +#ifndef _PHY_AM335x_H_ +#define _PHY_AM335x_H_ + +struct usb_phy *am335x_get_usb_phy(void); + +#endif |