diff options
Diffstat (limited to 'drivers/usb/dwc2')
-rw-r--r-- | drivers/usb/dwc2/Kconfig | 61 | ||||
-rw-r--r-- | drivers/usb/dwc2/Makefile | 37 | ||||
-rw-r--r-- | drivers/usb/dwc2/core.c | 68 | ||||
-rw-r--r-- | drivers/usb/dwc2/core.h | 182 | ||||
-rw-r--r-- | drivers/usb/dwc2/gadget.c | 3673 | ||||
-rw-r--r-- | drivers/usb/dwc2/hw.h | 12 | ||||
-rw-r--r-- | drivers/usb/dwc2/platform.c | 6 |
7 files changed, 4003 insertions, 36 deletions
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index be947d67384..f93807b3631 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -1,25 +1,58 @@ config USB_DWC2 - tristate "DesignWare USB2 DRD Core Support" + bool "DesignWare USB2 DRD Core Support" depends on USB help - Say Y or M here if your system has a Dual Role HighSpeed - USB controller based on the DesignWare HSOTG IP Core. + Say Y here if your system has a Dual Role Hi-Speed USB + controller based on the DesignWare HSOTG IP Core. - If you choose to build this driver as dynamically linked - modules, the core module will be called dwc2.ko, the - PCI bus interface module (if you have a PCI bus system) - will be called dwc2_pci.ko and the platform interface module - (for controllers directly connected to the CPU) will be called - dwc2_platform.ko. + For host mode, if you choose to build the driver as dynamically + linked modules, the core module will be called dwc2.ko, the PCI + bus interface module (if you have a PCI bus system) will be + called dwc2_pci.ko, and the platform interface module (for + controllers directly connected to the CPU) will be called + dwc2_platform.ko. For gadget mode, there will be a single + module called dwc2_gadget.ko. - NOTE: This driver at present only implements the Host mode - of the controller. The existing s3c-hsotg driver supports - Peripheral mode, but only for the Samsung S3C platforms. - There are plans to merge the s3c-hsotg driver with this - driver in the near future to create a dual-role driver. + NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The + host and gadget drivers are still currently separate drivers. + There are plans to merge the dwc2_gadget driver with the dwc2 + host driver in the near future to create a dual-role driver. if USB_DWC2 +config USB_DWC2_HOST + tristate "Host only mode" + depends on USB + help + The Designware USB2.0 high-speed host controller + integrated into many SoCs. + +config USB_DWC2_PLATFORM + bool "DWC2 Platform" + depends on USB_DWC2_HOST + default USB_DWC2_HOST + help + The Designware USB2.0 platform interface module for + controllers directly connected to the CPU. This is only + used for host mode. + +config USB_DWC2_PCI + bool "DWC2 PCI" + depends on USB_DWC2_HOST && PCI + default USB_DWC2_HOST + help + The Designware USB2.0 PCI interface module for controllers + connected to a PCI bus. This is only used for host mode. + +comment "Gadget mode requires USB Gadget support to be enabled" + +config USB_DWC2_PERIPHERAL + tristate "Gadget only mode" + depends on USB_GADGET + help + The Designware USB2.0 high-speed gadget controller + integrated into many SoCs. + config USB_DWC2_DEBUG bool "Enable Debugging Messages" help diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile index 11529d3439b..b73d2a52797 100644 --- a/drivers/usb/dwc2/Makefile +++ b/drivers/usb/dwc2/Makefile @@ -1,25 +1,28 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG -obj-$(CONFIG_USB_DWC2) += dwc2.o - -dwc2-y += core.o core_intr.o - -# NOTE: This driver at present only implements the Host mode -# of the controller. The existing s3c-hsotg driver supports -# Peripheral mode, but only for the Samsung S3C platforms. -# There are plans to merge the s3c-hsotg driver with this -# driver in the near future to create a dual-role driver. Once -# that is done, Host mode will become an optional feature that -# is selected with a config option. - +obj-$(CONFIG_USB_DWC2_HOST) += dwc2.o +dwc2-y := core.o core_intr.o dwc2-y += hcd.o hcd_intr.o dwc2-y += hcd_queue.o hcd_ddma.o -ifneq ($(CONFIG_PCI),) - obj-$(CONFIG_USB_DWC2) += dwc2_pci.o +# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to +# this location and renamed gadget.c. When building for dynamically linked +# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode, +# the core module will be dwc2.ko, the PCI bus interface module will called +# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko. +# At present the host and gadget driver will be separate drivers, but there +# are plans in the near future to create a dual-role driver. + +ifneq ($(CONFIG_USB_DWC2_PCI),) + obj-$(CONFIG_USB_DWC2_HOST) += dwc2_pci.o + dwc2_pci-y := pci.o +endif + +ifneq ($(CONFIG_USB_DWC2_PLATFORM),) + obj-$(CONFIG_USB_DWC2_HOST) += dwc2_platform.o + dwc2_platform-y := platform.o endif -obj-$(CONFIG_USB_DWC2) += dwc2_platform.o -dwc2_pci-y += pci.o -dwc2_platform-y += platform.o +obj-$(CONFIG_USB_DWC2_PERIPHERAL) += dwc2_gadget.o +dwc2_gadget-y := gadget.o diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 1d129884cc3..27d2c9b8a03 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -507,6 +507,72 @@ void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg) writel(intmsk, hsotg->regs + GINTMSK); } +/* + * dwc2_calculate_dynamic_fifo() - Calculates the default fifo size + * For system that have a total fifo depth that is smaller than the default + * RX + TX fifo size. + * + * @hsotg: Programming view of DWC_otg controller + */ +static void dwc2_calculate_dynamic_fifo(struct dwc2_hsotg *hsotg) +{ + struct dwc2_core_params *params = hsotg->core_params; + struct dwc2_hw_params *hw = &hsotg->hw_params; + u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size; + + total_fifo_size = hw->total_fifo_size; + rxfsiz = params->host_rx_fifo_size; + nptxfsiz = params->host_nperio_tx_fifo_size; + ptxfsiz = params->host_perio_tx_fifo_size; + + /* + * Will use Method 2 defined in the DWC2 spec: minimum FIFO depth + * allocation with support for high bandwidth endpoints. Synopsys + * defines MPS(Max Packet size) for a periodic EP=1024, and for + * non-periodic as 512. + */ + if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) { + /* + * For Buffer DMA mode/Scatter Gather DMA mode + * 2 * ((Largest Packet size / 4) + 1 + 1) + n + * with n = number of host channel. + * 2 * ((1024/4) + 2) = 516 + */ + rxfsiz = 516 + hw->host_channels; + + /* + * min non-periodic tx fifo depth + * 2 * (largest non-periodic USB packet used / 4) + * 2 * (512/4) = 256 + */ + nptxfsiz = 256; + + /* + * min periodic tx fifo depth + * (largest packet size*MC)/4 + * (1024 * 3)/4 = 768 + */ + ptxfsiz = 768; + + params->host_rx_fifo_size = rxfsiz; + params->host_nperio_tx_fifo_size = nptxfsiz; + params->host_perio_tx_fifo_size = ptxfsiz; + } + + /* + * If the summation of RX, NPTX and PTX fifo sizes is still + * bigger than the total_fifo_size, then we have a problem. + * + * We won't be able to allocate as many endpoints. Right now, + * we're just printing an error message, but ideally this FIFO + * allocation algorithm would be improved in the future. + * + * FIXME improve this FIFO allocation algorithm. + */ + if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz))) + dev_err(hsotg->dev, "invalid fifo sizes\n"); +} + static void dwc2_config_fifos(struct dwc2_hsotg *hsotg) { struct dwc2_core_params *params = hsotg->core_params; @@ -515,6 +581,8 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg) if (!params->enable_dynamic_fifo) return; + dwc2_calculate_dynamic_fifo(hsotg); + /* Rx FIFO */ grxfsiz = readl(hsotg->regs + GRXFSIZ); dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 648519c024b..1efd10cc962 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -37,6 +37,10 @@ #ifndef __DWC2_CORE_H__ #define __DWC2_CORE_H__ +#include <linux/phy/phy.h> +#include <linux/regulator/consumer.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> #include <linux/usb/phy.h> #include "hw.h" @@ -54,6 +58,184 @@ static inline void do_write(u32 value, void *addr) /* Maximum number of Endpoints/HostChannels */ #define MAX_EPS_CHANNELS 16 +/* s3c-hsotg declarations */ +static const char * const s3c_hsotg_supply_names[] = { + "vusb_d", /* digital USB supply, 1.2V */ + "vusb_a", /* analog USB supply, 1.1V */ +}; + +/* + * EP0_MPS_LIMIT + * + * Unfortunately there seems to be a limit of the amount of data that can + * be transferred by IN transactions on EP0. This is either 127 bytes or 3 + * packets (which practically means 1 packet and 63 bytes of data) when the + * MPS is set to 64. + * + * This means if we are wanting to move >127 bytes of data, we need to + * split the transactions up, but just doing one packet at a time does + * not work (this may be an implicit DATA0 PID on first packet of the + * transaction) and doing 2 packets is outside the controller's limits. + * + * If we try to lower the MPS size for EP0, then no transfers work properly + * for EP0, and the system will fail basic enumeration. As no cause for this + * has currently been found, we cannot support any large IN transfers for + * EP0. + */ +#define EP0_MPS_LIMIT 64 + +struct s3c_hsotg; +struct s3c_hsotg_req; + +/** + * struct s3c_hsotg_ep - driver endpoint definition. + * @ep: The gadget layer representation of the endpoint. + * @name: The driver generated name for the endpoint. + * @queue: Queue of requests for this endpoint. + * @parent: Reference back to the parent device structure. + * @req: The current request that the endpoint is processing. This is + * used to indicate an request has been loaded onto the endpoint + * and has yet to be completed (maybe due to data move, or simply + * awaiting an ack from the core all the data has been completed). + * @debugfs: File entry for debugfs file for this endpoint. + * @lock: State lock to protect contents of endpoint. + * @dir_in: Set to true if this endpoint is of the IN direction, which + * means that it is sending data to the Host. + * @index: The index for the endpoint registers. + * @mc: Multi Count - number of transactions per microframe + * @interval - Interval for periodic endpoints + * @name: The name array passed to the USB core. + * @halted: Set if the endpoint has been halted. + * @periodic: Set if this is a periodic ep, such as Interrupt + * @isochronous: Set if this is a isochronous ep + * @sent_zlp: Set if we've sent a zero-length packet. + * @total_data: The total number of data bytes done. + * @fifo_size: The size of the FIFO (for periodic IN endpoints) + * @fifo_load: The amount of data loaded into the FIFO (periodic IN) + * @last_load: The offset of data for the last start of request. + * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN + * + * This is the driver's state for each registered enpoint, allowing it + * to keep track of transactions that need doing. Each endpoint has a + * lock to protect the state, to try and avoid using an overall lock + * for the host controller as much as possible. + * + * For periodic IN endpoints, we have fifo_size and fifo_load to try + * and keep track of the amount of data in the periodic FIFO for each + * of these as we don't have a status register that tells us how much + * is in each of them. (note, this may actually be useless information + * as in shared-fifo mode periodic in acts like a single-frame packet + * buffer than a fifo) + */ +struct s3c_hsotg_ep { + struct usb_ep ep; + struct list_head queue; + struct s3c_hsotg *parent; + struct s3c_hsotg_req *req; + struct dentry *debugfs; + + unsigned long total_data; + unsigned int size_loaded; + unsigned int last_load; + unsigned int fifo_load; + unsigned short fifo_size; + + unsigned char dir_in; + unsigned char index; + unsigned char mc; + unsigned char interval; + + unsigned int halted:1; + unsigned int periodic:1; + unsigned int isochronous:1; + unsigned int sent_zlp:1; + + char name[10]; +}; + +/** + * struct s3c_hsotg - driver state. + * @dev: The parent device supplied to the probe function + * @driver: USB gadget driver + * @phy: The otg phy transceiver structure for phy control. + * @uphy: The otg phy transceiver structure for old USB phy control. + * @plat: The platform specific configuration data. This can be removed once + * all SoCs support usb transceiver. + * @regs: The memory area mapped for accessing registers. + * @irq: The IRQ number we are using + * @supplies: Definition of USB power supplies + * @phyif: PHY interface width + * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. + * @num_of_eps: Number of available EPs (excluding EP0) + * @debug_root: root directrory for debugfs. + * @debug_file: main status file for debugfs. + * @debug_fifo: FIFO status file for debugfs. + * @ep0_reply: Request used for ep0 reply. + * @ep0_buff: Buffer for EP0 reply data, if needed. + * @ctrl_buff: Buffer for EP0 control requests. + * @ctrl_req: Request for EP0 control packets. + * @setup: NAK management for EP0 SETUP + * @last_rst: Time of last reset + * @eps: The endpoints being supplied to the gadget framework + */ +struct s3c_hsotg { + struct device *dev; + struct usb_gadget_driver *driver; + struct phy *phy; + struct usb_phy *uphy; + struct s3c_hsotg_plat *plat; + + spinlock_t lock; + + void __iomem *regs; + int irq; + struct clk *clk; + + struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + + u32 phyif; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; + + struct dentry *debug_root; + struct dentry *debug_file; + struct dentry *debug_fifo; + + struct usb_request *ep0_reply; + struct usb_request *ctrl_req; + u8 ep0_buff[8]; + u8 ctrl_buff[8]; + + struct usb_gadget gadget; + unsigned int setup; + unsigned long last_rst; + struct s3c_hsotg_ep *eps; +}; + +/** + * struct s3c_hsotg_req - data transfer request + * @req: The USB gadget request + * @queue: The list of requests for the endpoint this is queued for. + * @in_progress: Has already had size/packets written to core + * @mapped: DMA buffer for this request has been mapped via dma_map_single(). + */ +struct s3c_hsotg_req { + struct usb_request req; + struct list_head queue; + unsigned char in_progress; + unsigned char mapped; +}; + +#define call_gadget(_hs, _entry) \ +do { \ + if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ + (_hs)->driver && (_hs)->driver->_entry) { \ + spin_unlock(&_hs->lock); \ + (_hs)->driver->_entry(&(_hs)->gadget); \ + spin_lock(&_hs->lock); \ + } \ +} while (0) + struct dwc2_hsotg; struct dwc2_host_chan; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c new file mode 100644 index 00000000000..f3c56a2fed5 --- /dev/null +++ b/drivers/usb/dwc2/gadget.c @@ -0,0 +1,3673 @@ +/** + * linux/drivers/usb/gadget/s3c-hsotg.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C USB2.0 High-speed / OtG driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/of_platform.h> +#include <linux/phy/phy.h> + +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/phy.h> +#include <linux/platform_data/s3c-hsotg.h> + +#include "core.h" + +/* conversion functions */ +static inline struct s3c_hsotg_req *our_req(struct usb_request *req) +{ + return container_of(req, struct s3c_hsotg_req, req); +} + +static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep) +{ + return container_of(ep, struct s3c_hsotg_ep, ep); +} + +static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget) +{ + return container_of(gadget, struct s3c_hsotg, gadget); +} + +static inline void __orr32(void __iomem *ptr, u32 val) +{ + writel(readl(ptr) | val, ptr); +} + +static inline void __bic32(void __iomem *ptr, u32 val) +{ + writel(readl(ptr) & ~val, ptr); +} + +/* forward decleration of functions */ +static void s3c_hsotg_dump(struct s3c_hsotg *hsotg); + +/** + * using_dma - return the DMA status of the driver. + * @hsotg: The driver state. + * + * Return true if we're using DMA. + * + * Currently, we have the DMA support code worked into everywhere + * that needs it, but the AMBA DMA implementation in the hardware can + * only DMA from 32bit aligned addresses. This means that gadgets such + * as the CDC Ethernet cannot work as they often pass packets which are + * not 32bit aligned. + * + * Unfortunately the choice to use DMA or not is global to the controller + * and seems to be only settable when the controller is being put through + * a core reset. This means we either need to fix the gadgets to take + * account of DMA alignment, or add bounce buffers (yuerk). + * + * Until this issue is sorted out, we always return 'false'. + */ +static inline bool using_dma(struct s3c_hsotg *hsotg) +{ + return false; /* support is not complete */ +} + +/** + * s3c_hsotg_en_gsint - enable one or more of the general interrupt + * @hsotg: The device state + * @ints: A bitmask of the interrupts to enable + */ +static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) +{ + u32 gsintmsk = readl(hsotg->regs + GINTMSK); + u32 new_gsintmsk; + + new_gsintmsk = gsintmsk | ints; + + if (new_gsintmsk != gsintmsk) { + dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); + writel(new_gsintmsk, hsotg->regs + GINTMSK); + } +} + +/** + * s3c_hsotg_disable_gsint - disable one or more of the general interrupt + * @hsotg: The device state + * @ints: A bitmask of the interrupts to enable + */ +static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) +{ + u32 gsintmsk = readl(hsotg->regs + GINTMSK); + u32 new_gsintmsk; + + new_gsintmsk = gsintmsk & ~ints; + + if (new_gsintmsk != gsintmsk) + writel(new_gsintmsk, hsotg->regs + GINTMSK); +} + +/** + * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq + * @hsotg: The device state + * @ep: The endpoint index + * @dir_in: True if direction is in. + * @en: The enable value, true to enable + * + * Set or clear the mask for an individual endpoint's interrupt + * request. + */ +static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, + unsigned int ep, unsigned int dir_in, + unsigned int en) +{ + unsigned long flags; + u32 bit = 1 << ep; + u32 daint; + + if (!dir_in) + bit <<= 16; + + local_irq_save(flags); + daint = readl(hsotg->regs + DAINTMSK); + if (en) + daint |= bit; + else + daint &= ~bit; + writel(daint, hsotg->regs + DAINTMSK); + local_irq_restore(flags); +} + +/** + * s3c_hsotg_init_fifo - initialise non-periodic FIFOs + * @hsotg: The device instance. + */ +static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) +{ + unsigned int ep; + unsigned int addr; + unsigned int size; + int timeout; + u32 val; + + /* set FIFO sizes to 2048/1024 */ + + writel(2048, hsotg->regs + GRXFSIZ); + writel((2048 << FIFOSIZE_STARTADDR_SHIFT) | + (1024 << FIFOSIZE_DEPTH_SHIFT), hsotg->regs + GNPTXFSIZ); + + /* + * arange all the rest of the TX FIFOs, as some versions of this + * block have overlapping default addresses. This also ensures + * that if the settings have been changed, then they are set to + * known values. + */ + + /* start at the end of the GNPTXFSIZ, rounded up */ + addr = 2048 + 1024; + size = 768; + + /* + * currently we allocate TX FIFOs for all possible endpoints, + * and assume that they are all the same size. + */ + + for (ep = 1; ep <= 15; ep++) { + val = addr; + val |= size << FIFOSIZE_DEPTH_SHIFT; + addr += size; + + writel(val, hsotg->regs + DPTXFSIZN(ep)); + } + + /* + * according to p428 of the design guide, we need to ensure that + * all fifos are flushed before continuing + */ + + writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | + GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); + + /* wait until the fifos are both flushed */ + timeout = 100; + while (1) { + val = readl(hsotg->regs + GRSTCTL); + + if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) + break; + + if (--timeout == 0) { + dev_err(hsotg->dev, + "%s: timeout flushing fifos (GRSTCTL=%08x)\n", + __func__, val); + } + + udelay(1); + } + + dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); +} + +/** + * @ep: USB endpoint to allocate request for. + * @flags: Allocation flags + * + * Allocate a new USB request structure appropriate for the specified endpoint + */ +static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, + gfp_t flags) +{ + struct s3c_hsotg_req *req; + + req = kzalloc(sizeof(struct s3c_hsotg_req), flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +/** + * is_ep_periodic - return true if the endpoint is in periodic mode. + * @hs_ep: The endpoint to query. + * + * Returns true if the endpoint is in periodic mode, meaning it is being + * used for an Interrupt or ISO transfer. + */ +static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) +{ + return hs_ep->periodic; +} + +/** + * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request + * @hsotg: The device state. + * @hs_ep: The endpoint for the request + * @hs_req: The request being processed. + * + * This is the reverse of s3c_hsotg_map_dma(), called for the completion + * of a request to ensure the buffer is ready for access by the caller. + */ +static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req) +{ + struct usb_request *req = &hs_req->req; + + /* ignore this if we're not moving any data */ + if (hs_req->req.length == 0) + return; + + usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); +} + +/** + * s3c_hsotg_write_fifo - write packet Data to the TxFIFO + * @hsotg: The controller state. + * @hs_ep: The endpoint we're going to write for. + * @hs_req: The request to write data for. + * + * This is called when the TxFIFO has some space in it to hold a new + * transmission and we have something to give it. The actual setup of + * the data size is done elsewhere, so all we have to do is to actually + * write the data. + * + * The return value is zero if there is more space (or nothing was done) + * otherwise -ENOSPC is returned if the FIFO space was used up. + * + * This routine is only needed for PIO + */ +static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req) +{ + bool periodic = is_ep_periodic(hs_ep); + u32 gnptxsts = readl(hsotg->regs + GNPTXSTS); + int buf_pos = hs_req->req.actual; + int to_write = hs_ep->size_loaded; + void *data; + int can_write; + int pkt_round; + int max_transfer; + + to_write -= (buf_pos - hs_ep->last_load); + + /* if there's nothing to write, get out early */ + if (to_write == 0) + return 0; + + if (periodic && !hsotg->dedicated_fifos) { + u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); + int size_left; + int size_done; + + /* + * work out how much data was loaded so we can calculate + * how much data is left in the fifo. + */ + + size_left = DXEPTSIZ_XFERSIZE_GET(epsize); + + /* + * if shared fifo, we cannot write anything until the + * previous data has been completely sent. + */ + if (hs_ep->fifo_load != 0) { + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); + return -ENOSPC; + } + + dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", + __func__, size_left, + hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); + + /* how much of the data has moved */ + size_done = hs_ep->size_loaded - size_left; + + /* how much data is left in the fifo */ + can_write = hs_ep->fifo_load - size_done; + dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", + __func__, can_write); + + can_write = hs_ep->fifo_size - can_write; + dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", + __func__, can_write); + + if (can_write <= 0) { + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); + return -ENOSPC; + } + } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { + can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index)); + + can_write &= 0xffff; + can_write *= 4; + } else { + if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { + dev_dbg(hsotg->dev, + "%s: no queue slots available (0x%08x)\n", + __func__, gnptxsts); + + s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); + return -ENOSPC; + } + + can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); + can_write *= 4; /* fifo size is in 32bit quantities. */ + } + + max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; + + dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", + __func__, gnptxsts, can_write, to_write, max_transfer); + + /* + * limit to 512 bytes of data, it seems at least on the non-periodic + * FIFO, requests of >512 cause the endpoint to get stuck with a + * fragment of the end of the transfer in it. + */ + if (can_write > 512 && !periodic) + can_write = 512; + + /* + * limit the write to one max-packet size worth of data, but allow + * the transfer to return that it did not run out of fifo space + * doing it. + */ + if (to_write > max_transfer) { + to_write = max_transfer; + + /* it's needed only when we do not use dedicated fifos */ + if (!hsotg->dedicated_fifos) + s3c_hsotg_en_gsint(hsotg, + periodic ? GINTSTS_PTXFEMP : + GINTSTS_NPTXFEMP); + } + + /* see if we can write data */ + + if (to_write > can_write) { + to_write = can_write; + pkt_round = to_write % max_transfer; + + /* + * Round the write down to an + * exact number of packets. + * + * Note, we do not currently check to see if we can ever + * write a full packet or not to the FIFO. + */ + + if (pkt_round) + to_write -= pkt_round; + + /* + * enable correct FIFO interrupt to alert us when there + * is more room left. + */ + + /* it's needed only when we do not use dedicated fifos */ + if (!hsotg->dedicated_fifos) + s3c_hsotg_en_gsint(hsotg, + periodic ? GINTSTS_PTXFEMP : + GINTSTS_NPTXFEMP); + } + + dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", + to_write, hs_req->req.length, can_write, buf_pos); + + if (to_write <= 0) + return -ENOSPC; + + hs_req->req.actual = buf_pos + to_write; + hs_ep->total_data += to_write; + + if (periodic) + hs_ep->fifo_load += to_write; + + to_write = DIV_ROUND_UP(to_write, 4); + data = hs_req->req.buf + buf_pos; + + iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); + + return (to_write >= can_write) ? -ENOSPC : 0; +} + +/** + * get_ep_limit - get the maximum data legnth for this endpoint + * @hs_ep: The endpoint + * + * Return the maximum data that can be queued in one go on a given endpoint + * so that transfers that are too long can be split. + */ +static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) +{ + int index = hs_ep->index; + unsigned maxsize; + unsigned maxpkt; + + if (index != 0) { + maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; + maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; + } else { + maxsize = 64+64; + if (hs_ep->dir_in) + maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; + else + maxpkt = 2; + } + + /* we made the constant loading easier above by using +1 */ + maxpkt--; + maxsize--; + + /* + * constrain by packet count if maxpkts*pktsize is greater + * than the length register size. + */ + + if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) + maxsize = maxpkt * hs_ep->ep.maxpacket; + + return maxsize; +} + +/** + * s3c_hsotg_start_req - start a USB request from an endpoint's queue + * @hsotg: The controller state. + * @hs_ep: The endpoint to process a request for + * @hs_req: The request to start. + * @continuing: True if we are doing more for the current request. + * + * Start the given request running by setting the endpoint registers + * appropriately, and writing any data to the FIFOs. + */ +static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, + struct s3c_hsotg_ep *hs_ep, + struct s3c_hsotg_req *hs_req, + bool continuing) +{ + struct usb_request *ureq = &hs_req->req; + int index = hs_ep->index; + int dir_in = hs_ep->dir_in; + u32 epctrl_reg; + u32 epsize_reg; + u32 epsize; + u32 ctrl; + unsigned length; + unsigned packets; + unsigned maxreq; + + if (index != 0) { + if (hs_ep->req && !continuing) { + dev_err(hsotg->dev, "%s: active request\n", __func__); + WARN_ON(1); + return; + } else if (hs_ep->req != hs_req && continuing) { + dev_err(hsotg->dev, + "%s: continue different req\n", __func__); + WARN_ON(1); + return; + } + } + + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); + epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", + __func__, readl(hsotg->regs + epctrl_reg), index, + hs_ep->dir_in ? "in" : "out"); + + /* If endpoint is stalled, we will restart request later */ + ctrl = readl(hsotg->regs + epctrl_reg); + + if (ctrl & DXEPCTL_STALL) { + dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); + return; + } + + length = ureq->length - ureq->actual; + dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", + ureq->length, ureq->actual); + if (0) + dev_dbg(hsotg->dev, + "REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n", + ureq->buf, length, &ureq->dma, + ureq->no_interrupt, ureq->zero, ureq->short_not_ok); + + maxreq = get_ep_limit(hs_ep); + if (length > maxreq) { + int round = maxreq % hs_ep->ep.maxpacket; + + dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", + __func__, length, maxreq, round); + + /* round down to multiple of packets */ + if (round) + maxreq -= round; + + length = maxreq; + } + + if (length) + packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); + else + packets = 1; /* send one packet if length is zero. */ + + if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { + dev_err(hsotg->dev, "req length > maxpacket*mc\n"); + return; + } + + if (dir_in && index != 0) + if (hs_ep->isochronous) + epsize = DXEPTSIZ_MC(packets); + else + epsize = DXEPTSIZ_MC(1); + else + epsize = 0; + + if (index != 0 && ureq->zero) { + /* + * test for the packets being exactly right for the + * transfer + */ + + if (length == (packets * hs_ep->ep.maxpacket)) + packets++; + } + + epsize |= DXEPTSIZ_PKTCNT(packets); + epsize |= DXEPTSIZ_XFERSIZE(length); + + dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", + __func__, packets, length, ureq->length, epsize, epsize_reg); + + /* store the request as the current one we're doing */ + hs_ep->req = hs_req; + + /* write size / packets */ + writel(epsize, hsotg->regs + epsize_reg); + + if (using_dma(hsotg) && !continuing) { + unsigned int dma_reg; + + /* + * write DMA address to control register, buffer already + * synced by s3c_hsotg_ep_queue(). + */ + + dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); + writel(ureq->dma, hsotg->regs + dma_reg); + + dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", + __func__, &ureq->dma, dma_reg); + } + + ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ + ctrl |= DXEPCTL_USBACTEP; + + dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); + + /* For Setup request do not clear NAK */ + if (hsotg->setup && index == 0) + hsotg->setup = 0; + else + ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ + + + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); + writel(ctrl, hsotg->regs + epctrl_reg); + + /* + * set these, it seems that DMA support increments past the end + * of the packet buffer so we need to calculate the length from + * this information. + */ + hs_ep->size_loaded = length; + hs_ep->last_load = ureq->actual; + + if (dir_in && !using_dma(hsotg)) { + /* set these anyway, we may need them for non-periodic in */ + hs_ep->fifo_load = 0; + + s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); + } + + /* + * clear the INTknTXFEmpMsk when we start request, more as a aide + * to debugging to see what is going on. + */ + if (dir_in) + writel(DIEPMSK_INTKNTXFEMPMSK, + hsotg->regs + DIEPINT(index)); + + /* |