Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee0db58a authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge branch 'for-gadget/next' of...

Merge branch 'for-gadget/next' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

* 'for-gadget/next' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (24 commits)
  usb: dwc3: gadget: add support for SG lists
  usb: dwc3: gadget: don't force 'LST' always
  usb: dwc3: gadget: don't return anything on prepare trbs
  usb: dwc3: gadget: re-factor dwc3_prepare_trbs()
  usb: gadget: introduce support for sg lists
  usb: renesas: pipe: convert a long if into a XOR operation
  usb: gadget: remove useless depends on Kconfig
  usb: gadget: s3c-hsudc: remove the_controller global
  usb: gadget: s3c-hsudc: use release_mem_region instead of release_resource
  usb: gadget: s3c-hsudc: Add regulator handling
  usb: gadget: s3c-hsudc: use udc_start and udc_stop functions
  usb: gadget: s3c-hsudc: move device registration to probe
  usb: gadget: s3c-hsudc: add missing otg_put_transceiver in probe
  usb: gadget: s3c-hsudc: add __devinit to probe function
  usb: gadget: s3c-hsudc: move platform_data struct to global header
  USB: EHCI: Add Marvell Host Controller driver
  USB: OTG: add Marvell usb OTG driver support
  usb: gadget: mv_udc: drop ARCH dependency
  usb: gadget: mv_udc: fix bug in ep_dequeue
  usb: gadget: enlarge maxburst bit width.
  ...
parents eea9fc7d eeb720fb
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@
#include <plat/nand.h>
#include <plat/nand.h>
#include <plat/sdhci.h>
#include <plat/sdhci.h>
#include <plat/udc.h>
#include <plat/udc.h>
#include <linux/platform_data/s3c-hsudc.h>


#include <plat/regs-fb-v4.h>
#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
#include <plat/fb.h>
+1 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/partitions.h>
#include <linux/mmc/host.h>
#include <linux/mmc/host.h>
#include <linux/ioport.h>
#include <linux/ioport.h>
#include <linux/platform_data/s3c-hsudc.h>


#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/pmu.h>
#include <asm/pmu.h>
+1 −14
Original line number Original line Diff line number Diff line
@@ -37,20 +37,7 @@ struct s3c2410_udc_mach_info {


extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);


/**
struct s3c24xx_hsudc_platdata;
 * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
 * @epnum: Number of endpoints to be instantiated by the controller driver.
 * @gpio_init: Platform specific USB related GPIO initialization.
 * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
 *
 * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
 * controllers.
 */
struct s3c24xx_hsudc_platdata {
	unsigned int	epnum;
	void		(*gpio_init)(void);
	void		(*gpio_uninit)(void);
};


extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);


+160 −79
Original line number Original line Diff line number Diff line
@@ -65,6 +65,22 @@ void dwc3_map_buffer_to_dma(struct dwc3_request *req)
		return;
		return;
	}
	}


	if (req->request.num_sgs) {
		int	mapped;

		mapped = dma_map_sg(dwc->dev, req->request.sg,
				req->request.num_sgs,
				req->direction ? DMA_TO_DEVICE
				: DMA_FROM_DEVICE);
		if (mapped < 0) {
			dev_err(dwc->dev, "failed to map SGs\n");
			return;
		}

		req->request.num_mapped_sgs = mapped;
		return;
	}

	if (req->request.dma == DMA_ADDR_INVALID) {
	if (req->request.dma == DMA_ADDR_INVALID) {
		req->request.dma = dma_map_single(dwc->dev, req->request.buf,
		req->request.dma = dma_map_single(dwc->dev, req->request.buf,
				req->request.length, req->direction
				req->request.length, req->direction
@@ -82,6 +98,17 @@ void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
		return;
		return;
	}
	}


	if (req->request.num_mapped_sgs) {
		req->request.dma = DMA_ADDR_INVALID;
		dma_unmap_sg(dwc->dev, req->request.sg,
				req->request.num_sgs,
				req->direction ? DMA_TO_DEVICE
				: DMA_FROM_DEVICE);

		req->request.num_mapped_sgs = 0;
		return;
	}

	if (req->mapped) {
	if (req->mapped) {
		dma_unmap_single(dwc->dev, req->request.dma,
		dma_unmap_single(dwc->dev, req->request.dma,
				req->request.length, req->direction
				req->request.length, req->direction
@@ -97,7 +124,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
	struct dwc3			*dwc = dep->dwc;
	struct dwc3			*dwc = dep->dwc;


	if (req->queued) {
	if (req->queued) {
		if (req->request.num_mapped_sgs)
			dep->busy_slot += req->request.num_mapped_sgs;
		else
			dep->busy_slot++;
			dep->busy_slot++;

		/*
		/*
		 * Skip LINK TRB. We can't use req->trb and check for
		 * Skip LINK TRB. We can't use req->trb and check for
		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
@@ -108,6 +139,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
			dep->busy_slot++;
			dep->busy_slot++;
	}
	}
	list_del(&req->list);
	list_del(&req->list);
	req->trb = NULL;


	if (req->request.status == -EINPROGRESS)
	if (req->request.status == -EINPROGRESS)
		req->request.status = status;
		req->request.status = status;
@@ -544,6 +576,85 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
	kfree(req);
	kfree(req);
}
}


/**
 * dwc3_prepare_one_trb - setup one TRB from one request
 * @dep: endpoint for which this request is prepared
 * @req: dwc3_request pointer
 */
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
		struct dwc3_request *req, dma_addr_t dma,
		unsigned length, unsigned last, unsigned chain)
{
	struct dwc3		*dwc = dep->dwc;
	struct dwc3_trb_hw	*trb_hw;
	struct dwc3_trb		trb;

	unsigned int		cur_slot;

	dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
			dep->name, req, (unsigned long long) dma,
			length, last ? " last" : "",
			chain ? " chain" : "");

	trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
	cur_slot = dep->free_slot;
	dep->free_slot++;

	/* Skip the LINK-TRB on ISOC */
	if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
			usb_endpoint_xfer_isoc(dep->desc))
		return;

	memset(&trb, 0, sizeof(trb));
	if (!req->trb) {
		dwc3_gadget_move_request_queued(req);
		req->trb = trb_hw;
		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
	}

	if (usb_endpoint_xfer_isoc(dep->desc)) {
		trb.isp_imi = true;
		trb.csp = true;
	} else {
		trb.chn = chain;
		trb.lst = last;
	}

	if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
		trb.sid_sofn = req->request.stream_id;

	switch (usb_endpoint_type(dep->desc)) {
	case USB_ENDPOINT_XFER_CONTROL:
		trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
		break;

	case USB_ENDPOINT_XFER_ISOC:
		trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;

		/* IOC every DWC3_TRB_NUM / 4 so we can refill */
		if (!(cur_slot % (DWC3_TRB_NUM / 4)))
			trb.ioc = last;
		break;

	case USB_ENDPOINT_XFER_BULK:
	case USB_ENDPOINT_XFER_INT:
		trb.trbctl = DWC3_TRBCTL_NORMAL;
		break;
	default:
		/*
		 * This is only possible with faulty memory because we
		 * checked it already :)
		 */
		BUG();
	}

	trb.length	= length;
	trb.bplh	= dma;
	trb.hwo		= true;

	dwc3_trb_to_hw(&trb, trb_hw);
}

/*
/*
 * dwc3_prepare_trbs - setup TRBs from requests
 * dwc3_prepare_trbs - setup TRBs from requests
 * @dep: endpoint for which requests are being prepared
 * @dep: endpoint for which requests are being prepared
@@ -553,18 +664,17 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
 * transfers. The functions returns once there are not more TRBs available or
 * transfers. The functions returns once there are not more TRBs available or
 * it run out of requests.
 * it run out of requests.
 */
 */
static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
		bool starting)
{
{
	struct dwc3_request	*req, *n, *ret = NULL;
	struct dwc3_request	*req, *n;
	struct dwc3_trb_hw	*trb_hw;
	struct dwc3_trb		trb;
	u32			trbs_left;
	u32			trbs_left;
	unsigned int		last_one = 0;


	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);


	/* the first request must not be queued */
	/* the first request must not be queued */
	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;

	/*
	/*
	 * if busy & slot are equal than it is either full or empty. If we are
	 * if busy & slot are equal than it is either full or empty. If we are
	 * starting to proceed requests then we are empty. Otherwise we ar
	 * starting to proceed requests then we are empty. Otherwise we ar
@@ -572,7 +682,7 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
	 */
	 */
	if (!trbs_left) {
	if (!trbs_left) {
		if (!starting)
		if (!starting)
			return NULL;
			return;
		trbs_left = DWC3_TRB_NUM;
		trbs_left = DWC3_TRB_NUM;
		/*
		/*
		 * In case we start from scratch, we queue the ISOC requests
		 * In case we start from scratch, we queue the ISOC requests
@@ -596,94 +706,62 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,


	/* The last TRB is a link TRB, not used for xfer */
	/* The last TRB is a link TRB, not used for xfer */
	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
		return NULL;
		return;


	list_for_each_entry_safe(req, n, &dep->request_list, list) {
	list_for_each_entry_safe(req, n, &dep->request_list, list) {
		unsigned int last_one = 0;
		unsigned	length;
		unsigned int cur_slot;
		dma_addr_t	dma;

		trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
		cur_slot = dep->free_slot;
		dep->free_slot++;

		/* Skip the LINK-TRB on ISOC */
		if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
				usb_endpoint_xfer_isoc(dep->desc))
			continue;


		dwc3_gadget_move_request_queued(req);
		if (req->request.num_mapped_sgs > 0) {
		memset(&trb, 0, sizeof(trb));
			struct usb_request *request = &req->request;
		trbs_left--;
			struct scatterlist *sg = request->sg;

			struct scatterlist *s;
		/* Is our TRB pool empty? */
			int		i;
		if (!trbs_left)
			last_one = 1;
		/* Is this the last request? */
		if (list_empty(&dep->request_list))
			last_one = 1;

		/*
		 * FIXME we shouldn't need to set LST bit always but we are
		 * facing some weird problem with the Hardware where it doesn't
		 * complete even though it has been previously started.
		 *
		 * While we're debugging the problem, as a workaround to
		 * multiple TRBs handling, use only one TRB at a time.
		 */
		last_one = 1;


		req->trb = trb_hw;
			for_each_sg(sg, s, request->num_mapped_sgs, i) {
		if (!ret)
				unsigned chain = true;
			ret = req;


		trb.bplh = req->request.dma;
				length = sg_dma_len(s);
				dma = sg_dma_address(s);


		if (usb_endpoint_xfer_isoc(dep->desc)) {
				if (i == (request->num_mapped_sgs - 1)
			trb.isp_imi = true;
						|| sg_is_last(s)) {
			trb.csp = true;
					last_one = true;
		} else {
					chain = false;
			trb.lst = last_one;
				}
				}


		if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
				trbs_left--;
			trb.sid_sofn = req->request.stream_id;
				if (!trbs_left)

					last_one = true;
		switch (usb_endpoint_type(dep->desc)) {
		case USB_ENDPOINT_XFER_CONTROL:
			trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
			break;


		case USB_ENDPOINT_XFER_ISOC:
				if (last_one)
			trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
					chain = false;


			/* IOC every DWC3_TRB_NUM / 4 so we can refill */
				dwc3_prepare_one_trb(dep, req, dma, length,
			if (!(cur_slot % (DWC3_TRB_NUM / 4)))
						last_one, chain);
				trb.ioc = last_one;
			break;


		case USB_ENDPOINT_XFER_BULK:
				if (last_one)
		case USB_ENDPOINT_XFER_INT:
			trb.trbctl = DWC3_TRBCTL_NORMAL;
					break;
					break;
		default:
			/*
			 * This is only possible with faulty memory because we
			 * checked it already :)
			 */
			BUG();
			}
			}
		} else {
			dma = req->request.dma;
			length = req->request.length;
			trbs_left--;


		trb.length	= req->request.length;
			if (!trbs_left)
		trb.hwo = true;
				last_one = 1;


		dwc3_trb_to_hw(&trb, trb_hw);
			/* Is this the last request? */
		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
			if (list_is_last(&req->list, &dep->request_list))
				last_one = 1;

			dwc3_prepare_one_trb(dep, req, dma, length,
					last_one, false);


			if (last_one)
			if (last_one)
				break;
				break;
		}
		}

	}
	return ret;
}
}


static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
@@ -712,11 +790,13 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
		/* req points to the first request which will be sent */
		/* req points to the first request which will be sent */
		req = next_request(&dep->req_queued);
		req = next_request(&dep->req_queued);
	} else {
	} else {
		dwc3_prepare_trbs(dep, start_new);

		/*
		/*
		 * req points to the first request where HWO changed
		 * req points to the first request where HWO changed
		 * from 0 to 1
		 * from 0 to 1
		 */
		 */
		req = dwc3_prepare_trbs(dep, start_new);
		req = next_request(&dep->req_queued);
	}
	}
	if (!req) {
	if (!req) {
		dep->flags |= DWC3_EP_PENDING_REQUEST;
		dep->flags |= DWC3_EP_PENDING_REQUEST;
@@ -2093,6 +2173,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
	dwc->gadget.max_speed		= USB_SPEED_SUPER;
	dwc->gadget.max_speed		= USB_SPEED_SUPER;
	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
	dwc->gadget.dev.parent		= dwc->dev;
	dwc->gadget.dev.parent		= dwc->dev;
	dwc->gadget.sg_supported	= true;


	dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
	dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);


+5 −9
Original line number Original line Diff line number Diff line
@@ -125,7 +125,6 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
#
#
choice
choice
	prompt "USB Peripheral Controller"
	prompt "USB Peripheral Controller"
	depends on USB_GADGET
	help
	help
	   A USB device uses a controller to talk to its host.
	   A USB device uses a controller to talk to its host.
	   Systems should have only one such upstream link.
	   Systems should have only one such upstream link.
@@ -310,13 +309,13 @@ config USB_S3C_HSUDC


	  This driver has been tested on S3C2416 and S3C2450 processors.
	  This driver has been tested on S3C2416 and S3C2450 processors.


config USB_PXA_U2O
config USB_MV_UDC
	tristate "PXA9xx Processor USB2.0 controller"
	tristate "Marvell USB2.0 Device Controller"
	depends on ARCH_MMP
	select USB_GADGET_DUALSPEED
	select USB_GADGET_DUALSPEED
	help
	help
	  PXA9xx Processor series include a high speed USB2.0 device
	  Marvell Socs (including PXA and MMP series) include a high speed
	  controller, which support high speed and full speed USB peripheral.
	  USB2.0 OTG controller, which can be configured as high speed or
	  full speed USB peripheral.


#
#
# Controllers available in both integrated and discrete versions
# Controllers available in both integrated and discrete versions
@@ -532,12 +531,10 @@ endchoice
# Selected by UDC drivers that support high-speed operation.
# Selected by UDC drivers that support high-speed operation.
config USB_GADGET_DUALSPEED
config USB_GADGET_DUALSPEED
	bool
	bool
	depends on USB_GADGET


# Selected by UDC drivers that support super-speed opperation
# Selected by UDC drivers that support super-speed opperation
config USB_GADGET_SUPERSPEED
config USB_GADGET_SUPERSPEED
	bool
	bool
	depends on USB_GADGET
	depends on USB_GADGET_DUALSPEED
	depends on USB_GADGET_DUALSPEED


#
#
@@ -545,7 +542,6 @@ config USB_GADGET_SUPERSPEED
#
#
choice
choice
	tristate "USB Gadget Drivers"
	tristate "USB Gadget Drivers"
	depends on USB_GADGET
	default USB_ETH
	default USB_ETH
	help
	help
	  A Linux "Gadget Driver" talks to the USB Peripheral Controller
	  A Linux "Gadget Driver" talks to the USB Peripheral Controller
Loading