Esempio n. 1
0
static void dwc2_ep0_start_out_transfer(struct dwc2 *dwc,
					struct dwc2_request *req) {
	dwc_otg_dev_out_ep_regs_t	*out_regs = dwc->dev_if.out_ep_regs[0];
	depctl_data_t			 depctl;
	struct dwc2_ep			*dep	  = req->dwc2_ep;
	deptsiz0_data_t			 deptsiz;

	deptsiz.d32 = dwc_readl(&out_regs->doeptsiz);
	deptsiz.b.xfersize = dep->maxp;
	deptsiz.b.supcnt = 0;
	deptsiz.b.pktcnt = 1;

	req->xfersize = dep->maxp;
	req->pktcnt = 1;

	DWC2_EP0_DEBUG_MSG("OUT: next_dma_addr = 0x%08x\n", req->next_dma_addr);

	if (dwc->dma_enable) {
		if (!dwc->dma_desc_enable) {
			dwc_writel(deptsiz.d32, &out_regs->doeptsiz);
			dwc_writel(req->next_dma_addr, &out_regs->doepdma);
		} else {
			/* TODO: Scatter/Gather DMA Mode here */
		}
	} else {
		dwc_writel(deptsiz.d32, &out_regs->doeptsiz);
	}

	/* EP enable */
	dep->flags |= DWC2_EP_BUSY;
	depctl.d32 = dwc_readl(&out_regs->doepctl);
	depctl.b.epena = 1;
	depctl.b.cnak = 1;
	dwc_writel(depctl.d32, &out_regs->doepctl);
}
void usb3_init_eventbuf(usb3_device_t *dev, int size, uint32_t dma_addr)
{
	dwc_writel(dma_addr & 0xffffffffU,
		 &dev->core_global_regs->geventbuf[0].geventadr_lo);
	dwc_writel(0, &dev->core_global_regs->geventbuf[0].geventadr_hi);
	dwc_writel(size << 2,
		 &dev->core_global_regs->geventbuf[0].geventsiz);
	dwc_writel(0, &dev->core_global_regs->geventbuf[0].geventcnt);
}
Esempio n. 3
0
static void dwc2_ep0_start_in_transfer(struct dwc2 *dwc,
				struct dwc2_request *req) {
	dwc_otg_dev_in_ep_regs_t	*in_regs = dwc->dev_if.in_ep_regs[0];
	struct dwc2_ep			*dep	 = req->dwc2_ep;
	depctl_data_t			 depctl;
	deptsiz0_data_t			 deptsiz;

	deptsiz.d32 = dwc_readl(&in_regs->dieptsiz);

	if (req->trans_count_left == 0) {
		/* Zero Packet */
		DWC2_EP0_DEBUG_MSG("IN zero packet\n");
		req->zlp_transfered = 1;
		deptsiz.b.xfersize = 0;
	} else {
		if (req->trans_count_left > dep->maxp) {
			deptsiz.b.xfersize = dep->maxp;
		} else {
			deptsiz.b.xfersize = req->trans_count_left;
		}
	}

	deptsiz.b.pktcnt = 1;

	req->xfersize = deptsiz.b.xfersize;
	req->pktcnt = 1;


	DWC2_EP0_DEBUG_MSG("IN: xfersize = %d next_dma_addr = 0x%08x zlp_transfered = %d dep->maxp = %d\n",
			req->xfersize, req->next_dma_addr, req->zlp_transfered, dep->maxp);

	/* Write the DMA register */
	if (dwc->dma_enable) {
		if (!dwc->dma_desc_enable) {
			dwc_writel(req->next_dma_addr, &in_regs->diepdma);
			dwc_writel(deptsiz.d32, &in_regs->dieptsiz);
		} else {
			/* TODO: Scatter/Gather DMA mode here */
		}
	} else {
		dwc_writel(deptsiz.d32, &in_regs->dieptsiz);
	}

	/* EP enable, IN data in FIFO */
	dep->flags |= DWC2_EP_BUSY;
	depctl.d32 = dwc_readl(&in_regs->diepctl);
	depctl.b.epena = 1;
	depctl.b.cnak = 1;
	dwc_writel(depctl.d32, &in_regs->diepctl);
}
Esempio n. 4
0
static void dwc2_ep0_complete_status(struct dwc2 *dwc) {
	struct dwc2_ep		*ep0	     = dwc2_ep0_get_ep0(dwc);
	struct dwc2_request	*curr_req;
	dctl_data_t		 dctl;

	/* enter test mode if needed (exit by reset) */
	if (dwc->test_mode) {
		/*
		 * The transition to test mode must be complete no later than 3 ms
		 * after the completion of the status stage of the request.
		 */
		dctl.d32 = dwc_readl(&dwc->dev_if.dev_global_regs->dctl);
		dctl.b.tstctl = dwc->test_mode_nr;
		dwc_writel(dctl.d32, &dwc->dev_if.dev_global_regs->dctl);
	}

	/*
	 * prepare to receive SETUP again to ensure we are prepared!!!
	 */
	dwc2_ep0_out_start(dwc);

	curr_req = next_request(&ep0->request_list);
	if (curr_req) {
		dwc2_gadget_giveback(ep0, curr_req, 0);
	}

	if (dwc->test_mode)
		dev_info(dwc->dev, "entering Test Mode(%d)\n", dwc->test_mode_nr);

	dwc->ep0state = EP0_SETUP_PHASE;
}
void usb3_dis_flush_eventbuf_intr(usb3_device_t *dev)
{
	uint32_t cnt;

	dis_eventbuf_intr(dev);
	cnt = dwc_readl(&dev->core_global_regs->geventbuf[0].geventcnt);
	dwc_writel(cnt, &dev->core_global_regs->geventbuf[0].geventcnt);
}
void usb3_enable_device_interrupts(usb3_device_t *dev)
{
	/* Clear any pending interrupts */
	usb3_dis_flush_eventbuf_intr(dev);

	/* Enable device interrupts */
	dwc_writel(USB3_DEVTEN_CONNDONE_BIT  | USB3_DEVTEN_USBRESET_BIT,
		 &dev->pcd.dev_global_regs->devten);
}
void ena_eventbuf_intr(usb3_device_t *dev)
{
	uint32_t eventsiz;

	eventsiz =
	      dwc_readl(&dev->core_global_regs->geventbuf[0].geventsiz);
	eventsiz &= ~USB3_EVENTSIZ_INT_MSK_BIT;
	dwc_writel(eventsiz,
        &dev->core_global_regs->geventbuf[0].geventsiz);
}
Esempio n. 8
0
/*
 * ch 9.4.1, 9.4.9
 */
static int dwc2_ep0_handle_feature(struct dwc2 *dwc,
				struct usb_ctrlrequest *ctrl, int set)
{
	struct dwc2_ep		*dep;
	u32			recip;
	u32			wValue;
	u32			wIndex;
	int			ret;
	gotgctl_data_t gotgctl = {.d32 = 0 };
	dwc_otg_core_global_regs_t *global_regs = dwc->core_global_regs;


	wValue = le16_to_cpu(ctrl->wValue);
	wIndex = le16_to_cpu(ctrl->wIndex);
	recip = ctrl->bRequestType & USB_RECIP_MASK;
	switch (recip) {
	case USB_RECIP_DEVICE:

		switch (wValue) {
		case USB_DEVICE_REMOTE_WAKEUP:
			dwc->remote_wakeup_enable = set;
			break;

		case USB_DEVICE_TEST_MODE:
			if ((wIndex & 0xff) != 0)
				return -EINVAL;
			/* 9.4.1: The Test_Mode feature cannot be cleared by the ClearFeature() request. */
			if (!set)
				return -EINVAL;
			/*
			 * The transition to test mode of an upstream facing port must not
			 * happen until after the status stage of the request.
			 *
			 * NOTE: we do not bother to check if the Test Mode Selector is valid,
			 *       the host must take care it!!!
			 */
			dwc->test_mode_nr = wIndex >> 8;
			dwc->test_mode = true;
			break;

		case USB_DEVICE_B_HNP_ENABLE:
			if (set) {
				dev_info(dwc->dev, "Request B HNP\n");

				dwc->b_hnp_enable = 1;
				// TODO: dwc_otg_pcd_update_otg(dwc, 0);

				/**
				 * TODO: Is the gotgctl.devhnpen cleared by a USB Reset?
				 */
				gotgctl.b.devhnpen = 1;
				gotgctl.b.hnpreq = 1;
				dwc_writel(gotgctl.d32, &global_regs->gotgctl);
			} else
				return -EINVAL;

			break;

		case USB_DEVICE_A_HNP_SUPPORT:
			if (set) {
				dwc->a_hnp_support = 1;
				// TODO: dwc_otg_pcd_update_otg(dwc, 0);
			} else
				return -EINVAL;

			break;

		case USB_DEVICE_A_ALT_HNP_SUPPORT:
			if (set) {
				dwc->a_alt_hnp_support = 1;
				// dwc_otg_pcd_update_otg(dwc, 0);
			} else
				return -EINVAL;

			break;

		default:
			return -EINVAL;
		}

		dwc2_ep0_do_status_phase(dwc);
		break;

	case USB_RECIP_INTERFACE:
		/* USB2.0 do not support interface feature */
		return -EINVAL;
		break;

	case USB_RECIP_ENDPOINT:
		switch (wValue) {
		case USB_ENDPOINT_HALT:
			dep = dwc2_wIndex_to_dep(dwc, wIndex);
			if (!dep)
				return -EINVAL;
			ret = __dwc2_gadget_ep_set_halt(dep, set);
			if (ret)
				return -EINVAL;
			break;
		default:
			return -EINVAL;
		}

		dwc2_ep0_do_status_phase(dwc);
		break;

	default:
		return -EINVAL;
	};

	return 0;
}

static int dwc2_ep0_std_request(struct dwc2 *dwc,
				struct usb_ctrlrequest *ctrl) {
	int ret;

	switch (ctrl->bRequest) {
	case USB_REQ_GET_STATUS:
		dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
		ret = dwc2_ep0_handle_status(dwc, ctrl);
		break;
	case USB_REQ_CLEAR_FEATURE:
		dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
		ret = dwc2_ep0_handle_feature(dwc, ctrl, 0);
		break;
	case USB_REQ_SET_FEATURE:
		dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
		ret = dwc2_ep0_handle_feature(dwc, ctrl, 1);
		break;
	case USB_REQ_SET_ADDRESS:
		dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
		ret = dwc2_ep0_set_address(dwc, ctrl);
		break;
	case USB_REQ_SET_CONFIGURATION:
		dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
		ret = dwc2_ep0_set_config(dwc, ctrl);
		break;
	default:
		dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
		ret = dwc2_ep0_delegate_req(dwc, ctrl);
		break;
	};

	return ret;
}
Esempio n. 9
0
/**
 * This function configures EPO to receive SETUP packets.
 *
 * Priciple: prepare to receive as sooooooon as the OUT ep is idle!
 */
void dwc2_ep0_out_start(struct dwc2 *dwc) {
	struct dwc2_dev_if	*dev_if	    = &dwc->dev_if;
	deptsiz0_data_t		 doeptsize0 = {.d32 = 0 };
	depctl_data_t		 doepctl    = {.d32 = 0 };
	doepmsk_data_t		 doepmsk;
	doepint_data_t		 doepint;
	u32			 doepdma;

	doepctl.d32 = dwc_readl(&dev_if->out_ep_regs[0]->doepctl);
	doeptsize0.d32 = dwc_readl(&dev_if->out_ep_regs[0]->doeptsiz);
	doepdma = dwc_readl(&dev_if->out_ep_regs[0]->doepdma);

	if (dwc->setup_prepared) {
		if (!doepctl.b.epena) {
			DWC2_EP0_DEBUG_MSG("setup prepared but ep0out is stoped by someone! "
					"doeptsize0 = 0x%08x doepdma = 0x%08x\n",
					doeptsize0.d32, doepdma);
		} else {
			DWC2_EP0_DEBUG_MSG("setup already prepared and ep0out is running! "
					"doeptsize0 = 0x%08x doepdma = 0x%08x\n",
					doeptsize0.d32, doepdma);
		}

		return;
	}

	if (unlikely(doepctl.b.epena)) {
		DWC2_EP0_DEBUG_MSG("ep0 is already enabled! doeptsize0 = 0x%08x\n", doeptsize0.d32);
		return;
	}

	doepmsk.d32 = dwc_readl(&dev_if->dev_global_regs->doepmsk);
	doepint.d32 = dwc_readl(&dev_if->out_ep_regs[0]->doepint) & doepmsk.d32;
	if (unlikely(doepint.b.setup)) {
		DWC2_EP0_DEBUG_MSG("%s: a setup packet is already pending\n", __func__);
		return;
	}

	dwc->setup_prepared = 1;

	doeptsize0.b.supcnt = 3;
	doeptsize0.b.pktcnt = 1;
	doeptsize0.b.xfersize = 8 * 3;

	if (dwc->dma_enable) {
		if (!dwc->dma_desc_enable) {
			/* TODO: if the endpoint is just transfering a SETUP packet,
			 * and we change these registers, what will happend?
			 *
			 * But how do we know that the core is just transfering a SETUP packet?
			 */

			dwc_writel(doeptsize0.d32, &dev_if->out_ep_regs[0]->doeptsiz);
			dwc_writel(dwc->ctrl_req_addr, &dev_if->out_ep_regs[0]->doepdma);
		} else {
			/* TODO: Scatter/Gather DMA here */
		}
	} else {
		dwc_writel(doeptsize0.d32, &dev_if->out_ep_regs[0]->doeptsiz);
	}

	DWC2_EP0_DEBUG_MSG("dwc2_ep0_out_start(0x%08x)\n", dwc->ctrl_req_addr);

	doepctl.b.cnak = 1;
	doepctl.b.epena = 1;
	dwc_writel(doepctl.d32, &dev_if->out_ep_regs[0]->doepctl);
}

static void dwc2_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)
{
	/* do nothing */
}

static void dwc2_ep0_start_transfer(struct dwc2 *dwc,
				struct dwc2_request *req);

/**
 * Problem: as soon as we receive the xfercompl intr for status phase,
 *       a new SETUP packet may comming, so we must prepare this.
 *
 * Solution: when do OUT status phase, call dwc2_ep0_out_start() instead,
 *
 *           when do IN status phase, firstly call dwc2_ep0_out_start(),
 *           then do a ZPL IN status transfer
 */
static int dwc2_ep0_do_status_phase(struct dwc2 *dwc) {
	unsigned	is_in = !dwc->ep0_expect_in;

	dwc->ep0state = EP0_STATUS_PHASE;
	dwc2_ep0_out_start(dwc);

	if (!is_in) {	      /* OUT status phase */
		return 0;
	} else {
		dwc->ep0_usb_req.dwc2_ep = dwc2_ep0_get_in_ep(dwc);
		dwc->ep0_usb_req.request.length = 0;
		dwc->ep0_usb_req.request.buf = (void *)0xFFFFFFFF;
		dwc->ep0_usb_req.request.complete = dwc2_ep0_status_cmpl;
		dwc2_ep0_start_transfer(dwc, &dwc->ep0_usb_req);
		return 0;
	}
}

/*
 * ch 9.4.6, the spec said:
 *     The USB device does not change its device address until after
 *     the Status stage of this request is completed successfully
 * TODO: do we need to set address after status stage compl?
 */
static int dwc2_ep0_set_address(struct dwc2 *dwc, struct usb_ctrlrequest *ctrl)
{
	dcfg_data_t	dcfg;
	u32		addr;

	addr = le16_to_cpu(ctrl->wValue);
	if (addr > 127) {
		dev_dbg(dwc->dev, "invalid device address %d\n", addr);
		return -EINVAL;
	}

	if (dwc->dev_state == DWC2_CONFIGURED_STATE) {
		dev_dbg(dwc->dev, "trying to set address when configured\n");
		return -EINVAL;
	}

	dcfg.d32 = dwc_readl(&dwc->dev_if.dev_global_regs->dcfg);
	dcfg.b.devaddr = addr;
	dwc_writel(dcfg.d32, &dwc->dev_if.dev_global_regs->dcfg);

	if (addr)
		dwc->dev_state = DWC2_ADDRESS_STATE;
	else
		dwc->dev_state = DWC2_DEFAULT_STATE;

	dwc2_ep0_do_status_phase(dwc);

	return 0;
}
void update_eventbuf_count(usb3_device_t *dev, int cnt)
{
	dwc_writel(cnt, &dev->core_global_regs->geventbuf[0].geventcnt);
}