Example #1
0
/**
 * Handler for the IN EP timeout handshake interrupt.
 */
static void handle_in_ep_timeout_intr(uint32_t _epnum)
{

        dctl_data_t dctl = { 0 };
        dwc_ep_t *ep = &g_dwc_eps[_epnum];

        gintmsk_data_t intr_mask = {0};


        /* Disable the NP Tx Fifo Empty Interrrupt */

	intr_mask.b.nptxfempty = 1;
	dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, 0);
        /** @todo NGS Check EP type.
         * Implement for Periodic EPs */
        /*
         * Non-periodic EP
         */
        /* Enable the Global IN NAK Effective Interrupt */
        intr_mask.b.ginnakeff = 1;
        dwc_modify_reg32( DWC_REG_GINTMSK, 0, intr_mask.d32);

        /* Set Global IN NAK */
        dctl.b.sgnpinnak = 1;
        dwc_modify_reg32( DWC_REG_DCTL,dctl.d32, dctl.d32);

        ep->stopped = 1;

}
Example #2
0
/**
 * handle the IN EP disable interrupt.
 */
static void handle_in_ep_disable_intr(uint32_t _epnum)
{
#if 0
        deptsiz_data_t dieptsiz = { 0 };
        dctl_data_t dctl = { 0 };
        depctl_data_t diepctl = { 0 };
        dwc_ep_t *ep = &g_dwc_eps[_epnum];

        if (ep->stopped) {
                /* Flush the Tx FIFO */
                /** @todo NGS: This is not the correct FIFO */
                dwc_otg_flush_tx_fifo( core_if, 0 );
                /* Clear the Global IN NP NAK */
                dctl.d32 = 0;
                dctl.b.cgnpinnak = 1;
                dwc_modify_reg32(&dev_if->in_ep_regs[_epnum]->diepctl,
                                 diepctl.d32, diepctl.d32);
                /* Restart the transaction */
                if (dieptsiz.b.pktcnt != 0 ||
                    dieptsiz.b.xfersize != 0) {
                        restart_transfer( _pcd, _epnum );
                }
        }
#endif
}
Example #3
0
int dwc_core_init()
{

    int32_t         snpsid;
    
    snpsid = dwc_read_reg32(DWC_REG_GSNPSID);

    if ((snpsid & 0xFFFFF000) != 0x4F542000) {
        ERR("Bad value for SNPSID: 0x%08x\n", snpsid);
        return -1;
    }

    ERR("dwc core init is ok!\n");// show printf is ok.
    /*
     * Disable the global interrupt until all the interrupt
     * handlers are installed.
     */
    gahbcfg_data_t  ahbcfg = {.d32 = 0 };
    ahbcfg.b.glblintrmsk = 1;   /* Enable interrupts bit */
    dwc_modify_reg32(DWC_REG_GAHBCFG, ahbcfg.d32, 0);
    /*
     * Initialize the DWC_otg core.
     */
    dwc_otg_core_init();

    dwc_modify_reg32(DWC_REG_DCTL,0,2);// Disconnect data line
    dwc_otg_pcd_init();
    dwc_modify_reg32(DWC_REG_DCTL,2,0);// Connect data line

    /*
     * Enable the global interrupt after all the interrupt
     * handlers are installed.
     */
    dwc_otg_enable_global_interrupts();

    return 0;
}

int
dwc_otg_irq()
{
	dwc_common_irq();
	dwc_pcd_irq();
	return 0;
}
static ssize_t pullup_store(struct device *_dev, struct device_attribute *attr,  const char *buf, size_t count)
{

	uint32_t val = 0;
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);

	if(strncmp(buf, "on", sizeof("on")-1) == 0)
		val = 1;
	else if(strncmp(buf, "off", sizeof("off")-1) == 0)
		val = 0;
	else
		val = simple_strtoul(buf, NULL, 16);
		
	msleep(1);	
	//printk("%s -%d\n",__func__,val);
	if (val & 1) {
		dwc_modify_reg32( &otg_dev->core_if->dev_if->dev_global_regs->dctl,2,0); //connect
	} else {
		dwc_modify_reg32( &otg_dev->core_if->dev_if->dev_global_regs->dctl,0,2);  //disconnect
	}

	return count;
}
Example #5
0
static void pcd_setup( pcd_struct_t *_pcd )
{

	struct usb_ctrlrequest	ctrl = _pcd->setup_pkt.req;
	dwc_ep_t	*ep0 = &g_dwc_eps[0];
	deptsiz0_data_t doeptsize0 = { 0};

	if(_pcd->request_enable == 0)
		return;

//	_pcd->setup_pkt.d32[0] = 0;
//	_pcd->setup_pkt.d32[1] = 0;
	unsigned short status = 0;
	_pcd->request_enable = 0;

        doeptsize0.d32 = dwc_read_reg32( DWC_REG_OUT_EP_TSIZE(0));

        if (ctrl.bRequestType & USB_DIR_IN) {        
                ep0->is_in = 1;
                _pcd->ep0state = EP0_IN_DATA_PHASE;
        } else {
                ep0->is_in = 0;
                _pcd->ep0state = EP0_OUT_DATA_PHASE;
        }


	if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) {
		/* handle non-standard (class/vendor) requests in the gadget driver */
		//do_gadget_setup(_pcd, &ctrl );
		DBG("Vendor requset\n");
		do_vendor_request(_pcd, &ctrl );
		dwc_otg_ep_req_start(_pcd,0);
		return;
	}

        /** @todo NGS: Handle bad setup packet? */

        switch (ctrl.bRequest) {

        case USB_REQ_GET_STATUS:

                switch (ctrl.bRequestType & USB_RECIP_MASK) {
                case USB_RECIP_DEVICE:
                        status = 0x1; /* Self powered */
                        status |= 0;//_pcd->remote_wakeup_enable << 1; 
                        break;
		}
		_pcd->buf = (char *)&status;
		_pcd->length = 2;
		dwc_otg_ep_req_start(_pcd,0);
		break;
#if 0
                case USB_RECIP_INTERFACE:
                        *status = 0;
                        break;                        

                case USB_RECIP_ENDPOINT:
                        ep = get_ep_by_addr(_pcd, ctrl.wIndex);
                        if ( ep == 0 || ctrl.wLength > 2) {
                                ep0_do_stall(_pcd, -EOPNOTSUPP);
                                return;
                        }
                        /** @todo check for EP stall */
                        *status = ep->stopped;
                        break;
                }
                _pcd->ep0_pending = 1;

                ep0->dwc_ep.start_xfer_buff = (uint8_t *)status;
                ep0->dwc_ep.xfer_buff = (uint8_t *)status;
                ep0->dwc_ep.dma_addr = _pcd->status_buf_dma_handle;
                ep0->dwc_ep.xfer_len = 2;
                ep0->dwc_ep.xfer_count = 0;
                ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
                dwc_otg_ep0_start_transfer( GET_CORE_IF(_pcd), &ep0->dwc_ep );
                break;

        case USB_REQ_CLEAR_FEATURE:
                do_clear_feature( _pcd );
                break;

        case USB_REQ_SET_FEATURE:
                do_set_feature( _pcd );
                break;
 #endif               
        case USB_REQ_SET_ADDRESS:
                if (ctrl.bRequestType == USB_RECIP_DEVICE) {
                        dcfg_data_t dcfg = { 0 };

			    //DBG("Set address: %d\n",ctrl.wValue);
                        dcfg.b.devaddr = ctrl.wValue;
                        dwc_modify_reg32(DWC_REG_DCFG,0, dcfg.d32);
                        do_setup_in_status_phase( _pcd );
                        return;
                }
                break;

        case USB_REQ_SET_INTERFACE:
        case USB_REQ_SET_CONFIGURATION:
                _pcd->request_config = 1;   /* Configuration changed */
               // do_gadget_setup(_pcd, &ctrl );
               // break;
                
        default:
                /* Call the Gadget Driver's setup functions */        
                do_gadget_setup(_pcd, &ctrl );
                dwc_otg_ep_req_start(_pcd,0);
		break;
        }
Example #6
0
/**
 * This function is used to submit an I/O Request to an EP.
 *
 *	- When the request completes the request's completion callback
 *	  is called to return the request to the driver.
 *	- An EP, except control EPs, may have multiple requests
 *	  pending.
 *	- Once submitted the request cannot be examined or modified.
 *	- Each request is turned into one or more packets.
 *	- A BULK EP can queue any amount of data; the transfer is
 *	  packetized.
 *	- Zero length Packets are specified with the request 'zero'
 *	  flag.
 */
static int dwc_otg_pcd_ep_queue(struct usb_ep *_ep, 
								struct usb_request *_req, int _gfp_flags)
{
	int prevented = 0;
	dwc_otg_pcd_request_t *req;
	dwc_otg_pcd_ep_t *ep;
	dwc_otg_pcd_t	*pcd;
	unsigned long flags = 0;

	DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p,%d)\n", 
				__func__, _ep, _req, _gfp_flags);
		
	req = container_of(_req, dwc_otg_pcd_request_t, req);
	if (!_req || !_req->complete || !_req->buf || 
			!list_empty(&req->queue)) 
	{
		if( !_req ) printk("bad _req\n");
		if( !_req->complete ) printk("bad _req->complete\n");
		if( !_req->buf ) printk("bad _req->buf\n");
		if( !list_empty(&req->queue) ) printk("bad list_empty\n");
		DWC_WARN("%s, bad params\n", __func__);
		return -EINVAL;
	}
		
	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
	if (!_ep || (!ep->desc && ep->dwc_ep.num != 0)) 
	{
		DWC_WARN("%s, bad ep\n", __func__);
		return -EINVAL;
	}
	pcd = ep->pcd;

//cathy, if suspended, drop request
	if ( (GET_CORE_IF(pcd)->dev_if->suspended == 1) && (ep->dwc_ep.num != 0) )
	{
		DWC_DEBUGPL(DBG_PCDV,"%s, epnum = %d, drop request\n", __func__, ep->dwc_ep.num);
		return -ESHUTDOWN;	
	}

	if (!pcd->driver || pcd->gadget.speed == USB_SPEED_UNKNOWN) 
	{
		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", pcd->gadget.speed);
		DWC_WARN("%s, bogus device state\n", __func__);
		return -ESHUTDOWN;
	}


	DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
				   _ep->name, _req, _req->length, _req->buf);

	if (!GET_CORE_IF(pcd)->core_params->opt) 
	{
		if (ep->dwc_ep.num != 0) 
		{
			DWC_ERROR("%s queue req %p, len %d buf %p\n",
					  _ep->name, _req, _req->length, _req->buf);
		}
	}

	SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);

#if defined(DEBUG) & defined(VERBOSE)
	dump_msg(_req->buf, _req->length);
#endif	

	_req->status = -EINPROGRESS;
	_req->actual = 0;

	/* 
	 * For EP0 IN without premature status, zlp is required?
	 */
	if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) 
	{
		DWC_DEBUGPL(DBG_PCDV, "%s-OUT ZLP\n", _ep->name);
		//_req->zero = 1;
	}

	/* Start the transfer */
	if (list_empty(&ep->queue) && !ep->stopped) 
	{
		/* EP0 Transfer? */
		if (ep->dwc_ep.num == 0) 
		{
			switch (pcd->ep0state) 
			{
			case EP0_IN_DATA_PHASE:
				DWC_DEBUGPL(DBG_PCD, 
								"%s ep0: EP0_IN_DATA_PHASE\n", 
								__func__);
				break;

			case EP0_OUT_DATA_PHASE:
				DWC_DEBUGPL(DBG_PCD, 
								"%s ep0: EP0_OUT_DATA_PHASE\n", 
								__func__);
				if (pcd->request_config) 
				{ 
					/* Complete STATUS PHASE */
					ep->dwc_ep.is_in = 1;
					pcd->ep0state = EP0_STATUS;
				}
				break;
						
			default:
				DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n", 
											pcd->ep0state);
				SPIN_UNLOCK_IRQRESTORE(&pcd->lock, flags);
				return -EL2HLT;
			}
			ep->dwc_ep.dma_addr = (u32)_req->buf & ~Uncache_Mask;   //_req->dma;	//cathy
			ep->dwc_ep.start_xfer_buff = _req->buf;
			ep->dwc_ep.xfer_buff = _req->buf;
			ep->dwc_ep.xfer_len = _req->length;
			ep->dwc_ep.xfer_count = 0;
			ep->dwc_ep.sent_zlp = 0;
			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
			dwc_otg_ep0_start_transfer( GET_CORE_IF(pcd), 
										&ep->dwc_ep );
		} 
		else 
		{
			/* Setup and start the Transfer */
			ep->dwc_ep.dma_addr = (u32)_req->buf  & ~Uncache_Mask;   //_req->dma;	//cathy
			//ep->dwc_ep.dma_addr = _req->dma;
			ep->dwc_ep.start_xfer_buff = _req->buf;
			ep->dwc_ep.xfer_buff = _req->buf;
			ep->dwc_ep.xfer_len = _req->length;
			ep->dwc_ep.xfer_count = 0;
			ep->dwc_ep.sent_zlp = 0;
			ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
			dwc_otg_ep_start_transfer( GET_CORE_IF(pcd), 
									   &ep->dwc_ep );
		}
	}

	if ((req != 0) || prevented) 
	{
		++pcd->request_pending;
		list_add_tail(&req->queue, &ep->queue);
//cathy
#if 0
		if (ep->dwc_ep.is_in && ep->stopped && !(GET_CORE_IF(pcd)->dma_enable)) 
		{
			/** @todo NGS Create a function for this. */
			diepmsk_data_t diepmsk = { .d32 = 0};
			diepmsk.b.intktxfemp = 1;
			dwc_modify_reg32( &GET_CORE_IF(pcd)->dev_if->dev_global_regs->diepmsk, 0, diepmsk.d32 );
		}
#endif		
	}
/**
 * This function handles the OTG Interrupts. It reads the OTG
 * Interrupt Register (GOTGINT) to determine what interrupt has
 * occurred.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *core_if)
{
	dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
	gotgint_data_t gotgint;
	gotgctl_data_t gotgctl;
	gintmsk_data_t gintmsk;
	gpwrdn_data_t gpwrdn;

	gotgint.d32 = dwc_read_reg32(&global_regs->gotgint);
	gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
		    op_state_str(core_if));

	if (gotgint.b.sesenddet) {
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "Session End Detected++ (%s)\n",
			    op_state_str(core_if));
		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);

		if (core_if->op_state == B_HOST) {
			cil_pcd_start(core_if);
			core_if->op_state = B_PERIPHERAL;
		} else {
			/* If not B_HOST and Device HNP still set. HNP
			 * Did not succeed!*/
			if (gotgctl.b.devhnpen) {
				DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
				__DWC_ERROR
				    ("Device Not Connected/Responding!\n");
			}

			/* If Session End Detected the B-Cable has
			 * been disconnected. */
			/* Reset PCD and Gadget driver to a
			 * clean state. */
			core_if->lx_state = DWC_OTG_L0;
			cil_pcd_stop(core_if);

			if (core_if->adp_enable) {
				if (core_if->power_down == 2) {
					gpwrdn.d32 = 0;
					gpwrdn.b.pwrdnswtch = 1;
					dwc_modify_reg32(&core_if->
							 core_global_regs->
							 gpwrdn, gpwrdn.d32, 0);
				}

				gpwrdn.d32 = 0;
				gpwrdn.b.pmuactv = 1;
				dwc_modify_reg32(&core_if->core_global_regs->
						 gpwrdn, 0, gpwrdn.d32);

				dwc_otg_adp_sense_start(core_if);
			}
		}

		gotgctl.d32 = 0;
		gotgctl.b.devhnpen = 1;
		dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
	}
	if (gotgint.b.sesreqsucstschng) {
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "Session Reqeust Success Status Change++\n");
		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
		if (gotgctl.b.sesreqscs) {
			if ((core_if->core_params->phy_type ==
			     DWC_PHY_TYPE_PARAM_FS)
			    && (core_if->core_params->i2c_enable)) {
				core_if->srp_success = 1;
			} else {
				cil_pcd_resume(core_if);
				/* Clear Session Request */
				gotgctl.d32 = 0;
				gotgctl.b.sesreq = 1;
				dwc_modify_reg32(&global_regs->gotgctl,
						 gotgctl.d32, 0);
			}
		}
	}
	if (gotgint.b.hstnegsucstschng) {
		/* Print statements during the HNP interrupt handling
		 * can cause it to fail.*/
		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
		if (gotgctl.b.hstnegscs) {
			if (dwc_otg_is_host_mode(core_if)) {
				core_if->op_state = B_HOST;
				/*
				 * Need to disable SOF interrupt immediately.
				 * When switching from device to host, the PCD
				 * interrupt handler won't handle the
				 * interrupt if host mode is already set. The
				 * HCD interrupt handler won't get called if
				 * the HCD state is HALT. This means that the
				 * interrupt does not get handled and Linux
				 * complains loudly.
				 */
				gintmsk.d32 = 0;
				gintmsk.b.sofintr = 1;
				dwc_modify_reg32(&global_regs->gintmsk,
						 gintmsk.d32, 0);
				cil_pcd_stop(core_if);
				/*
				 * Initialize the Core for Host mode.
				 */
				cil_hcd_start(core_if);
				core_if->op_state = B_HOST;
			}
		} else {
			gotgctl.d32 = 0;
			gotgctl.b.hnpreq = 1;
			gotgctl.b.devhnpen = 1;
			dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
			DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
			__DWC_ERROR("Device Not Connected/Responding\n");
			/* Stop and re-start PCD to move back to B_PERIPHERAL state */
			cil_pcd_stop(core_if);
			cil_pcd_start(core_if);
			core_if->op_state = B_PERIPHERAL;
		}
	}
	if (gotgint.b.hstnegdet) {
		/* The disconnect interrupt is set at the same time as
		 * Host Negotiation Detected.  During the mode
		 * switch all interrupts are cleared so the disconnect
		 * interrupt handler will not get executed.
		 */
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "Host Negotiation Detected++ (%s)\n",
			    (dwc_otg_is_host_mode(core_if) ? "Host" :
			     "Device"));
		if (dwc_otg_is_device_mode(core_if)) {
			DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
				    core_if->op_state);
			cil_hcd_disconnect(core_if);
			cil_pcd_start(core_if);
			core_if->op_state = A_PERIPHERAL;
		} else {
			/*
			 * Need to disable SOF interrupt immediately. When
			 * switching from device to host, the PCD interrupt
			 * handler won't handle the interrupt if host mode is
			 * already set. The HCD interrupt handler won't get
			 * called if the HCD state is HALT. This means that
			 * the interrupt does not get handled and Linux
			 * complains loudly.
			 */
			gintmsk.d32 = 0;
			gintmsk.b.sofintr = 1;
			dwc_modify_reg32(&global_regs->gintmsk, gintmsk.d32, 0);
			cil_pcd_stop(core_if);
			cil_hcd_start(core_if);
			core_if->op_state = A_HOST;
		}
	}
	if (gotgint.b.adevtoutchng)
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
			    "A-Device Timeout Change++\n");

	if (gotgint.b.debdone)
		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");

	/* Clear GOTGINT */
	dwc_write_reg32(&core_if->core_global_regs->gotgint, gotgint.d32);

	return 1;
}
/**
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume
 * signaling. The handler schedules a time to stop resume signaling.
 */
int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t *core_if)
{
	gintsts_data_t gintsts;

	DWC_DEBUGPL(DBG_ANY,
		    "++Resume and Remote Wakeup Detected Interrupt++\n");

	DWC_DEBUGPL(DBG_PCD,
			"%s lxstate = %d\n", __func__, core_if->lx_state);

#ifdef CONFIG_USB_OTG_UTILS
	if (core_if->xceiver->set_suspend &&
	    (core_if->lx_state == DWC_OTG_L2) &&
	    !core_if->core_params->otg_supp_enable) {

#ifdef CONFIG_USB_DELAYED_SUSPEND_POWER_SAVING
		/* We can see a reset before suspend processing
		 * gets scheduled. Cancel it since we don't want to
		 * suspend after seeing reset
		 */
		DWC_TIMER_CANCEL(core_if->suspend_power_saving_timer);
#else
		/* REVISIT when we use the external wake interrupt */
		usb_phy_set_suspend(core_if->xceiver, 0);
#endif

	}
#endif

	if (dwc_otg_is_device_mode(core_if)) {
		dctl_data_t dctl = {.d32 = 0 };
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
			    dwc_read_reg32(&core_if->dev_if->dev_global_regs->
					   dsts));
		if (core_if->lx_state == DWC_OTG_L2) {
#ifdef PARTIAL_POWER_DOWN
			if (core_if->hwcfg4.b.power_optimiz) {
				pcgcctl_data_t power = {.d32 = 0 };

				power.d32 = dwc_read_reg32(core_if->pcgcctl);
				DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
					    power.d32);

				power.b.stoppclk = 0;
				dwc_write_reg32(core_if->pcgcctl, power.d32);

				power.b.pwrclmp = 0;
				dwc_write_reg32(core_if->pcgcctl, power.d32);

				power.b.rstpdwnmodule = 0;
				dwc_write_reg32(core_if->pcgcctl, power.d32);
			}
#endif
			/* Clear the Remote Wakeup Signaling */
			dctl.b.rmtwkupsig = 1;
			dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
					 dctl, dctl.d32, 0);

			if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
				core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
							       p);
			}
		} else {
			glpmcfg_data_t lpmcfg;
			lpmcfg.d32 =
			    dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
			lpmcfg.b.hird_thres &= (~(1 << 4));
			dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
					lpmcfg.d32);
		}
		/** Change to L0 state*/
		core_if->lx_state = DWC_OTG_L0;
	} else {
		if (core_if->lx_state != DWC_OTG_L1) {
void w_conn_id_status_change(void *p)
{
	dwc_otg_core_if_t *core_if = p;
	uint32_t count = 0;
	gotgctl_data_t gotgctl = {.d32 = 0 };

	gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);

	/* B-Device connector (Device Mode) */
	if (gotgctl.b.conidsts) {
		/* Wait for switch to device mode. */
		while (!dwc_otg_is_device_mode(core_if)) {
			DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
#ifdef CONFIG_USB_OTG_UTILS
		if (core_if->xceiver->otg->set_vbus)
			core_if->xceiver->otg->set_vbus(core_if->xceiver->otg, false);
#endif
		core_if->op_state = B_PERIPHERAL;
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_pcd_start(core_if);
	} else {
		/* A-Device connector (Host Mode) */
		while (!dwc_otg_is_host_mode(core_if)) {
			DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
				   (dwc_otg_is_host_mode(core_if) ? "Host" :
				    "Peripheral"));
			dwc_mdelay(100);
			if (++count > 10000)
				break;
		}
		DWC_ASSERT(++count < 10000,
			   "Connection id status change timed out");
		core_if->op_state = A_HOST;
		/*
		 * Initialize the Core for Host mode.
		 */
		dwc_otg_core_init(core_if);
		dwc_otg_enable_global_interrupts(core_if);
		cil_hcd_start(core_if);
	}
}

/**
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition.
 *
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *core_if)
{

	/*
	 * Need to disable SOF interrupt immediately. If switching from device
	 * to host, the PCD interrupt handler won't handle the interrupt if
	 * host mode is already set. The HCD interrupt handler won't get
	 * called if the HCD state is HALT. This means that the interrupt does
	 * not get handled and Linux complains loudly.
	 */
	gintmsk_data_t gintmsk = {.d32 = 0 };
	gintsts_data_t gintsts = {.d32 = 0 };

	gintmsk.b.sofintr = 1;
	dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);

	DWC_DEBUGPL(DBG_CIL,
		    " ++Connector ID Status Change Interrupt++  (%s)\n",
		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));

	/*
	 * Need to schedule a work, as there are possible DELAY function calls
	 */
	DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
			   core_if, "connection id status change");

	/* Set flag and clear interrupt */
	gintsts.b.conidstschng = 1;
	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

/**
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power.
 *
 * @param core_if Programming view of DWC_otg controller.
 */
int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t *core_if)
{
	hprt0_data_t hprt0;
	gintsts_data_t gintsts;

#ifndef DWC_HOST_ONLY
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");

	if (dwc_otg_is_device_mode(core_if)) {
		DWC_PRINTF("SRP: Device mode\n");
	} else {
		DWC_PRINTF("SRP: Host mode\n");
		/* Turn on the port power bit. */
		hprt0.d32 = dwc_otg_read_hprt0(core_if);
		hprt0.b.prtpwr = 1;
		dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);

#ifdef CONFIG_USB_OTG
		if (core_if->core_params->otg_supp_enable) {
			/* Schedule a work item to init the core */
			DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_init_core,
					   core_if, "SRP detected");
		} else
#endif
		{
			/* Start the Connection timer. So a message can be displayed
			 * if connect does not occur within connection wait timeout */
			cil_hcd_session_start(core_if);
		}
	}
#endif

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.sessreqintr = 1;
	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);

	return 1;
}

void w_wakeup_detected(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;
	/*
	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
	 * so that OPT tests pass with all PHYs).
	 */
	hprt0_data_t hprt0 = {.d32 = 0 };
#if 0
	pcgcctl_data_t pcgcctl = {.d32 = 0 };
	/* Restart the Phy Clock */
	pcgcctl.b.stoppclk = 1;
	dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
	dwc_udelay(10);
#endif /*0 */
	hprt0.d32 = dwc_otg_read_hprt0(core_if);
	DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
/*      dwc_mdelay(70); */
	hprt0.b.prtres = 0;	/* Resume */
	dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
	DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
		    dwc_read_reg32(core_if->host_if->hprt0));

	cil_hcd_resume(core_if);

	/** Change to L0 state*/
	core_if->lx_state = DWC_OTG_L0;
}

void w_a_periph_done(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;

	if (core_if->op_state == A_PERIPHERAL) {
		/* Clear the a_peripheral flag, back to a_host. */
		cil_pcd_stop(core_if);
		cil_hcd_start(core_if);
		core_if->op_state = A_HOST;
	}
}

void w_peri_suspend_powersaving(void *p)
{
	dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *)p;

	if (core_if) {
		/* Clear DWC Core interrupts before PHY suspend,
		   this is because to prevent DWC core Hangs while 
		   accessing some registers with PHY suspended if at
		   all we get some core interrupts when phy in suspend*/

		/* Clear any pending OTG Interrupts */
		dwc_write_reg32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);

		/* Clear any pending interrupts */
		dwc_write_reg32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);

		dwc_otg_disable_global_interrupts(core_if);		

		/* Suspend trasceiver */
		usb_phy_set_suspend(core_if->xceiver, 1);
	}
}
Example #10
0
void dwc_otg_pullup(int is_on)
{
	if(is_on)
		dwc_modify_reg32(DWC_REG_DCTL,2,0);// connect data line
	else dwc_modify_reg32(DWC_REG_DCTL,0,2);// disconnect data line
}
Example #11
0
/**
 * This function handles the Connector ID Status Change Interrupt.  It
 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
 * is a Device to Host Mode transition or a Host Mode to Device
 * Transition.  
 *
 * This only occurs when the cable is connected/removed from the PHY
 * connector.
 *
 * @param _core_if Programming view of DWC_otg controller.
 */ 
int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *
						      _core_if) 
{
	uint32_t count = 0;
	gintsts_data_t gintsts = {.d32 = 0};
	gintmsk_data_t gintmsk = {.d32 = 0};
	gotgctl_data_t gotgctl = {.d32 = 0};
	
	/*
	 * Need to disable SOF interrupt immediately. If switching from device
	 * to host, the PCD interrupt handler won't handle the interrupt if
	 * host mode is already set. The HCD interrupt handler won't get
	 * called if the HCD state is HALT. This means that the interrupt does
	 * not get handled and Linux complains loudly.
	 */ 
	gintmsk.b.sofintr = 1;
	dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
	DWC_DEBUGPL(DBG_CIL,
		      " ++Connector ID Status Change Interrupt++  (%s)\n",
		      (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"));
	gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
	
	/* B-Device connector (Device Mode) */ 
	if (gotgctl.b.conidsts) {
		
		/* Wait for switch to device mode. */ 
		while (!dwc_otg_is_device_mode(_core_if)) {
			DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n", 
				   (dwc_otg_is_host_mode(_core_if) ? "Host" :
				    "Peripheral"));
			MDELAY(100);
			if (++count > 10000)
				*(uint32_t *) NULL = 0;
		}
		_core_if->op_state = B_PERIPHERAL;
		dwc_otg_core_init(_core_if);
		dwc_otg_enable_global_interrupts(_core_if);
		pcd_start(_core_if);
	} else {
		
		/* A-Device connector (Host Mode) */ 
		while (!dwc_otg_is_host_mode(_core_if)) {
			DWC_PRINT("Waiting for Host Mode, Mode=%s\n", 
				   (dwc_otg_is_host_mode(_core_if) ? "Host" :
				    "Peripheral"));
			MDELAY(100);
			if (++count > 10000)
				*(uint32_t *) NULL = 0;
		}
		_core_if->op_state = A_HOST;
		
		/*
		 * Initialize the Core for Host mode.
		 */ 
		dwc_otg_core_init(_core_if);
		dwc_otg_enable_global_interrupts(_core_if);
		hcd_start(_core_if);
	}
	
	/* Set flag and clear interrupt */ 
	gintsts.b.conidstschng = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that a device is initiating the Session
 * Request Protocol to request the host to turn on bus power so a new
 * session can begin. The handler responds by turning on bus power. If
 * the DWC_otg controller is in low power mode, the handler brings the
 * controller out of low power mode before turning on bus power. 
 *
 * @param _core_if Programming view of DWC_otg controller.
 */ 
int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	
#ifndef DWC_HOST_ONLY
	hprt0_data_t hprt0;
	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		DWC_PRINT("SRP: Device mode\n");
	} else {
		DWC_PRINT("SRP: Host mode\n");
		
		/* Turn on the port power bit. */ 
		hprt0.d32 = dwc_otg_read_hprt0(_core_if);
		hprt0.b.prtpwr = 1;
		dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
		
		/* Start the Connection timer. So a message can be displayed
		 * if connect does not occur within 10 seconds. */ 
		hcd_session_start(_core_if);
	}
	
#endif	/*  */
	    
	/* Clear interrupt */ 
	gintsts.d32 = 0;
	gintsts.b.sessreqintr = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that the DWC_otg controller has detected a
 * resume or remote wakeup sequence. If the DWC_otg controller is in
 * low power mode, the handler must brings the controller out of low
 * power mode. The controller automatically begins resume
 * signaling. The handler schedules a time to stop resume signaling.
 */ 
int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	DWC_DEBUGPL(DBG_ANY,"++Resume and Remote Wakeup Detected Interrupt++\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		dctl_data_t dctl = {.d32 = 0};
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
				dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts));
		
#ifdef PARTIAL_POWER_DOWN
		if (_core_if->hwcfg4.b.power_optimiz) {
			pcgcctl_data_t power = {.d32 = 0};
			power.d32 = dwc_read_reg32(_core_if->pcgcctl);
			DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32);
			power.b.stoppclk = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.pwrclmp = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.rstpdwnmodule = 0;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
		}
		
#endif	/*  */
		/* Clear the Remote Wakeup Signalling */ 
		dctl.b.rmtwkupsig = 1;
		dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dctl,
				  dctl.d32, 0);
		if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup) {
			_core_if->pcd_cb->resume_wakeup(_core_if->pcd_cb->p);
		}
	} else {
		
		/*
		 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
		 * so that OPT tests pass with all PHYs).
		 */ 
		hprt0_data_t hprt0 = {.d32 = 0};
		pcgcctl_data_t pcgcctl = {.d32 = 0};
		
		/* Restart the Phy Clock */ 
		pcgcctl.b.stoppclk = 1;
		dwc_modify_reg32(_core_if->pcgcctl, pcgcctl.d32, 0);
		UDELAY(10);
		
		/* Now wait for 70 ms. */ 
		hprt0.d32 = dwc_otg_read_hprt0(_core_if);
		DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
		MDELAY(70);
		hprt0.b.prtres = 0;	/* Resume */
		dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32);
		DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
			     dwc_read_reg32(_core_if->host_if->hprt0));
	}
	
	/* Clear interrupt */ 
	gintsts.d32 = 0;
	gintsts.b.wkupintr = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/** 
 * This interrupt indicates that a device has been disconnected from
 * the root port. 
 */ 
int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * _core_if) 
{
	gintsts_data_t gintsts;
	printk(KERN_ERR "  Disconnect Detected Interrupt++ (%s) %s\n", 
		 (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"),
		 op_state_str(_core_if));
	DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
		     (dwc_otg_is_host_mode(_core_if) ? "Host" : "Device"),
		     op_state_str(_core_if));
	
/** @todo Consolidate this if statement. */ 
#ifndef DWC_HOST_ONLY
	if (_core_if->op_state == B_HOST) {
		
		/* If in device mode Disconnect and stop the HCD, then
		 * start the PCD. */ 
		hcd_disconnect(_core_if);
		pcd_start(_core_if);
		_core_if->op_state = B_PERIPHERAL;
	} else if (dwc_otg_is_device_mode(_core_if)) {
		gotgctl_data_t gotgctl = {.d32 = 0};
		gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl);
		if (gotgctl.b.hstsethnpen == 1) {
			/* Do nothing, if HNP in process the OTG
			 * interrupt "Host Negotiation Detected"
			 * interrupt will do the mode switch.
			 */ 
		} else if (gotgctl.b.devhnpen == 0) {
			/* If in device mode Disconnect and stop the HCD, then
			 * start the PCD. */ 
			hcd_disconnect(_core_if);
			pcd_start(_core_if);
			_core_if->op_state = B_PERIPHERAL;
		} else {
			DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
		}
	} else {
		if (_core_if->op_state == A_HOST) {
			/* A-Cable still connected but device disconnected. */ 
			hcd_disconnect(_core_if);
		}
	}
	
#endif	/*  */
	gintsts.d32 = 0;
	gintsts.b.disconnect = 1;
	dwc_write_reg32(&_core_if->core_global_regs->gintsts, gintsts.d32);
	return 1;
}

/**
 * This interrupt indicates that SUSPEND state has been detected on
 * the USB.
 * 
 * For HNP the USB Suspend interrupt signals the change from
 * "a_peripheral" to "a_host".
 *
 * When power management is enabled the core will be put in low power
 * mode.
 */ 
int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * _core_if) 
{
	dsts_data_t dsts;
	gintsts_data_t gintsts;
	DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
	if (dwc_otg_is_device_mode(_core_if)) {
		
		/* Check the Device status register to determine if the Suspend
		 * state is active. */ 
		dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts);
		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
		DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d " 
			     "HWCFG4.power Optimize=%d\n", dsts.b.suspsts,
			     _core_if->hwcfg4.b.power_optimiz);
		
#ifdef PARTIAL_POWER_DOWN
/** @todo Add a module parameter for power management. */ 
		if (dsts.b.suspsts && _core_if->hwcfg4.b.power_optimiz) {
			pcgcctl_data_t power = {.d32 = 0};
			DWC_DEBUGPL(DBG_CIL, "suspend\n");
			power.b.pwrclmp = 1;
			dwc_write_reg32(_core_if->pcgcctl, power.d32);
			power.b.rstpdwnmodule = 1;
			dwc_modify_reg32(_core_if->pcgcctl, 0, power.d32);
			power.b.stoppclk = 1;
			dwc_modify_reg32(_core_if->pcgcctl, 0, power.d32);
		} else {
			DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
		}
		
#endif	/*  */
		/* PCD callback for suspend. */ 
		pcd_suspend(_core_if);
	} else {
		if (_core_if->op_state == A_PERIPHERAL) {
Example #12
0
/**
 * This interrupt indicates that an IN EP has a pending Interrupt.
 * The sequence for handling the IN EP interrupt is shown below:
 * -#	Read the Device All Endpoint Interrupt register
 * -#	Repeat the following for each IN EP interrupt bit set (from
 *   	LSB to MSB).
 * -#	Read the Device Endpoint Interrupt (DIEPINTn) register
 * -#	If "Transfer Complete" call the request complete function
 * -#	If "Endpoint Disabled" complete the EP disable procedure.
 * -#	If "AHB Error Interrupt" log error
 * -#	If "Time-out Handshake" log error
 * -#	If "IN Token Received when TxFIFO Empty" write packet to Tx
 *   	FIFO.
 * -#	If "IN Token EP Mismatch" (disable, this is handled by EP
 *   	Mismatch Interrupt)
 */
static int32_t dwc_otg_pcd_handle_in_ep_intr(void)
{
#define CLEAR_IN_EP_INTR(__epnum,__intr) \
do { \
        diepint_data_t diepint = { 0 }; \
	diepint.b.__intr = 1; \
	dwc_write_reg32(DWC_REG_IN_EP_INTR(__epnum), \
			diepint.d32); \
} while (0)

        diepint_data_t diepint = { 0 };
//        depctl_data_t diepctl = { 0 };
        uint32_t ep_intr;
        uint32_t epnum = 0;
        gintmsk_data_t intr_mask = {0};
        gintsts_data_t gintsts;

	 DBG( "dwc_otg_pcd_handle_in_ep_intr()\n" );

	/* Read in the device interrupt bits */
        ep_intr = (dwc_read_reg32(DWC_REG_DAINT) &
                dwc_read_reg32( DWC_REG_DAINTMSK));
        ep_intr =( (ep_intr & 0xffff) );


	/* Clear the INEPINT in GINTSTS */
	/* Clear all the interrupt bits for all IN endpoints in DAINT */
	gintsts.d32 = 0;
	gintsts.b.inepint = 1;
	dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32);
	dwc_write_reg32(DWC_REG_DAINT, 0xFFFF );
	flush_cpu_cache();

	/* Service the Device IN interrupts for each endpoint */
        while ( ep_intr ) {
                if (ep_intr&0x1) {

                        diepint.d32 = (dwc_read_reg32( DWC_REG_IN_EP_INTR(epnum)) &
									dwc_read_reg32(DWC_REG_DAINTMSK));
                        /* Transfer complete */
                        if ( diepint.b.xfercompl ) {


                                /* Disable the NP Tx FIFO Empty
                                 * Interrrupt */
                                intr_mask.b.nptxfempty = 1;
                                dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, 0);

                                /* Clear the bit in DIEPINTn for this interrupt */
                                CLEAR_IN_EP_INTR(epnum,xfercompl);

                                /* Complete the transfer */
					if (epnum == 0) {
						handle_ep0( 0 );
					} else {
						complete_ep( epnum,1 );
					}
                        }
                        /* Endpoint disable  */
                        if ( diepint.b.epdisabled ) {
                                handle_in_ep_disable_intr( epnum );

                                /* Clear the bit in DIEPINTn for this interrupt */
                                CLEAR_IN_EP_INTR(epnum,epdisabled);
                        }
                        /* AHB Error */
                        if ( diepint.b.ahberr ) {
				/* Clear the bit in DIEPINTn for this interrupt */
				CLEAR_IN_EP_INTR(epnum,ahberr);
                        }
                        /* TimeOUT Handshake (non-ISOC IN EPs) */
                        if ( diepint.b.timeout ) {
                                handle_in_ep_timeout_intr( epnum );

				CLEAR_IN_EP_INTR(epnum,timeout);
                        }
                        /** IN Token received with TxF Empty */
                        if (diepint.b.intktxfemp) {
                                DWN_MSG("diepint.b.intktxfemp\n");
#if 0
                                if (!ep->stopped && epnum != 0) {
                                        diepmsk_data_t diepmsk = { 0};
                                        diepmsk.b.intktxfemp = 1;
                                        dwc_modify_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32, 0 );
                                        start_next_request(ep);
                                }
#endif
				CLEAR_IN_EP_INTR(epnum,intktxfemp);
                        }
                        /** IN Token Received with EP mismatch */
                        if (diepint.b.intknepmis) {
                                DWN_MSG("intknepmis ep%d\n", epnum);
                                CLEAR_IN_EP_INTR(epnum,intknepmis);
                        }
                        /** IN Endpoint NAK Effective */
                        if (diepint.b.inepnakeff) {
				CLEAR_IN_EP_INTR(epnum,inepnakeff);
                        }
                }
                epnum++;
                ep_intr >>=1;
        }

        return 1;

#undef CLEAR_IN_EP_INTR
}
Example #13
0
/**
 * Read the device status register and set the device speed in the
 * data structure.
 * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
 */
int32_t dwc_otg_pcd_handle_enum_done_intr(void)
{
	gintsts_data_t gintsts;
	gusbcfg_data_t gusbcfg;
	/*dsts_data_t dsts;*/
	depctl_data_t diepctl;
	depctl_data_t doepctl;
	dctl_data_t dctl ={0};

	DBG("SPEED ENUM\n");

	/* Read the Device Status and Endpoint 0 Control registers */
	/*dsts.d32 = dwc_read_reg32(DWC_REG_DSTS);*/
	diepctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(0) );
	doepctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0));

	/* Set the MPS of the IN EP based on the enumeration speed */
	diepctl.b.mps = DWC_DEP0CTL_MPS_64;
	dwc_write_reg32(DWC_REG_IN_EP_REG(0) , diepctl.d32);

	/* Enable OUT EP for receive */
	doepctl.b.epena = 1;
	dwc_write_reg32(DWC_REG_OUT_EP_REG(0), doepctl.d32);

	dctl.b.cgnpinnak = 1;
	dwc_modify_reg32(DWC_REG_DCTL, dctl.d32, dctl.d32);

        if (this_pcd[0].ep0state == EP0_DISCONNECT) {
				this_pcd[0].ep0state = EP0_IDLE;
		} else if (this_pcd[0].ep0state == EP0_STALL) {
				this_pcd[0].ep0state = EP0_IDLE;
        }

    this_pcd[0].ep0state = EP0_IDLE;


	/* Set USB turnaround time based on device speed and PHY interface. */
	gusbcfg.d32 = dwc_read_reg32(DWC_REG_GUSBCFG);
#if 0
	if (_pcd->gadget.speed == USB_SPEED_HIGH) {
		if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
			/* ULPI interface */
			gusbcfg.b.usbtrdtim = 9;
		}
		if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
			/* UTMI+ interface */
			if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16) {
				gusbcfg.b.usbtrdtim = 5;
			} else {
				gusbcfg.b.usbtrdtim = 9;
			}
		}
		if (GET_CORE_IF(_pcd)->hwcfg2.b.hs_phy_type == DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
			/* UTMI+  OR  ULPI interface */
			if (gusbcfg.b.ulpi_utmi_sel == 1) {
				/* ULPI interface */
				gusbcfg.b.usbtrdtim = 9;
			} else {
				/* UTMI+ interface */
				if (GET_CORE_IF(_pcd)->core_params->phy_utmi_width == 16) {
					gusbcfg.b.usbtrdtim = 5;
				} else {
					gusbcfg.b.usbtrdtim = 9;
				}
			}
		}
	} else {
		/* Full or low speed */
		gusbcfg.b.usbtrdtim = 9;
	}
#else
	/* Full or low speed */
	gusbcfg.b.usbtrdtim = 5;
#endif
	dwc_write_reg32(DWC_REG_GUSBCFG, gusbcfg.d32);

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.enumdone = 1;
	dwc_write_reg32(DWC_REG_GINTSTS,gintsts.d32 );
	return 1;
}
Example #14
0
/**
 * This function handles the Rx Status Queue Level Interrupt, which
 * indicates that there is a least one packet in the Rx FIFO.  The
 * packets are moved from the FIFO to memory, where they will be
 * processed when the Endpoint Interrupt Register indicates Transfer
 * Complete or SETUP Phase Done.
 *
 * Repeat the following until the Rx Status Queue is empty:
 *   -#	Read the Receive Status Pop Register (GRXSTSP) to get Packet
 *     	info
 *   -#	If Receive FIFO is empty then skip to step Clear the interrupt
 *     	and exit
 *   -#	If SETUP Packet call dwc_otg_read_setup_packet to copy the
 *   	SETUP data to the buffer
 *   -#	If OUT Data Packet call dwc_otg_read_packet to copy the data
 *     	to the destination buffer
 */
int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(void)
{
    gintmsk_data_t gintmask = { 0 };
    device_grxsts_data_t status;
    gintsts_data_t gintsts;
    dwc_ep_t *ep;


    DBG("dwc_otg_pcd_handle_rx_status_q_level_intr()\n");
    /* Disable the Rx Status Queue Level interrupt */
    gintmask.b.rxstsqlvl= 1;
    dwc_modify_reg32( DWC_REG_GINTMSK, gintmask.d32, 0);

    /* Get the Status from the top of the FIFO */
    status.d32 = dwc_read_reg32( DWC_REG_GRXSTSP);

    //DBG("rx status: ep%d, pktsts: %d\n",status.b.epnum,status.b.pktsts);

    /* Get pointer to EP structure */
    ep = &g_dwc_eps[status.b.epnum];

    switch (status.b.pktsts)
    {
        case DWC_DSTS_GOUT_NAK:
            DBG( "Global OUT NAK\n");
            break;

        case DWC_STS_DATA_UPDT:
            DBG( "OUT Data Packet\n");
            {
                if (status.b.bcnt && ep->xfer_buff)
                {
                    /** @todo NGS Check for buffer overflow? */
                    dwc_otg_read_packet( ep->xfer_buff,status.b.bcnt);
                    ep->xfer_count += status.b.bcnt;
                    ep->xfer_buff += status.b.bcnt;

                    if (!status.b.epnum)
                    {
                        /*const char* p = ep->xfer_buff - status.b.bcnt;*/
                        this_pcd[0].cmdtype.out_complete = 1;
                        /*
                         *if(!strcmp("power", p) || !strcmp("low_power", p)){
                         *    printf("%s, bcnt %d, cnt %d, %d\n", p, status.b.bcnt, ep->xfer_count, this_pcd.cmdtype.in_complete);
                         *}
                         */
                    }
                }
            }
            break;

        case DWC_STS_XFER_COMP:
            DBG("OUT Complete\n");
            break;

        case DWC_DSTS_SETUP_COMP:
            DBG("SETUP Complete\n");
            break;

        case DWC_DSTS_SETUP_UPDT:
            DBG("SETUP update\n");
            {
                static int _is_first_setup_out_in_cmd = 1;

                dwc_otg_read_setup_packet( this_pcd[0].setup_pkt.d32);
                this_pcd[0].request_enable = 1;
                ep->xfer_count += status.b.bcnt;

                DBG("set %d, %d\n", status.b.bcnt, ep->xfer_count);
                if (_is_first_setup_out_in_cmd) //first tplcmd/bulkcmd that in sequence 'setup + out + in'
                {
                    struct usb_ctrlrequest request = this_pcd[0].setup_pkt.req;
                    if ( USB_TYPE_VENDOR == (request.bRequestType & USB_TYPE_MASK) )
                    {
                        unsigned bRequest = request.bRequest;

                        if ((AM_REQ_WR_LARGE_MEM == bRequest) || (AM_REQ_RD_LARGE_MEM == bRequest)
                                ||(AM_REQ_TPL_CMD == bRequest) || (AM_REQ_TPL_STAT == bRequest)
                                || (AM_REQ_DOWNLOAD == bRequest) || (AM_REQ_BULKCMD == bRequest))
                        {
                            __udelay(20);//delay for first command that consisted of consecutive 'ep0 out', i.e. 'setup + out + in'
                            _is_first_setup_out_in_cmd = 0;
                        }
                    }
                }
            }
        break;

        default:
            //DBG( "Invalid Packet Status (0x%0x)\n", status.b.pktsts);
            break;

    }

    /* Enable the Rx Status Queue Level interrupt */
    dwc_modify_reg32( DWC_REG_GINTMSK, 0, gintmask.d32);
    /* Clear interrupt */
    gintsts.d32 = 0;
    gintsts.b.rxstsqlvl = 1;
    dwc_write_reg32 ( DWC_REG_GINTSTS, gintsts.d32);

    return 1;
}
Example #15
0
/**
 * This interrupt occurs when a USB Reset is detected.  When the USB
 * Reset Interrupt occurs the device state is set to DEFAULT and the
 * EP0 state is set to IDLE.
 *  -#	Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
 *  -#	Unmask the following interrupt bits
 *  	- DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
 * 	- DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
 * 	- DOEPMSK.SETUP = 1
 * 	- DOEPMSK.XferCompl = 1
 * 	- DIEPMSK.XferCompl = 1
 *	- DIEPMSK.TimeOut = 1
 *  -# Program the following fields in the endpoint specific registers
 *  for Control OUT EP 0, in order to receive a setup packet
 * 	- DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back
 * 	  setup packets)
 *	- DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back
 *	  to back setup packets)
 *      - In DMA mode, DOEPDMA0 Register with a memory address to
 *        store any setup packets received
 * At this point, all the required initialization, except for enabling
 * the control 0 OUT endpoint is done, for receiving SETUP packets.
 */
int32_t dwc_otg_pcd_handle_usb_reset_intr(void)
{

        depctl_data_t doepctl = { 0};
        daint_data_t daintmsk = { 0};
        doepmsk_data_t doepmsk = { 0};
        diepmsk_data_t diepmsk = { 0};
        dcfg_data_t dcfg = { 0 };
        depctl_data_t diepctl = { 0};
        depctl_data_t diepctl_rd = { 0};
        grstctl_t resetctl = { 0 };
        dctl_data_t dctl = { 0 };
        int i = 0;
        gintsts_data_t gintsts;


        DBG("\nUSB RESET\n");


        /* Clear the Remote Wakeup Signalling */
        dctl.b.rmtwkupsig = 1;
        dwc_modify_reg32( DWC_REG_DCTL,dctl.d32, 0 );

        /* Disable all active IN EPs */
        diepctl.b.epdis = 1;
        diepctl.b.snak = 1;
        for (i=0; i < NUM_EP; i++) {
                diepctl_rd.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(i));
                if (diepctl_rd.b.epena) {
                        dwc_write_reg32(DWC_REG_IN_EP_REG(i),diepctl.d32 );
                }
        }

        /* Set NAK for all OUT EPs */
        doepctl.b.snak = 1;
        for (i=0; i < NUM_EP; i++) {
                dwc_write_reg32(DWC_REG_OUT_EP_REG(i), doepctl.d32 );
        }

        /* Flush the NP Tx FIFO */
        dwc_otg_flush_tx_fifo( 0 );
        /* Flush the Learning Queue */
        resetctl.b.intknqflsh = 1;
        dwc_write_reg32( DWC_REG_GRSTCTL, resetctl.d32);

        daintmsk.b.inep0 = 1;
        daintmsk.b.outep0 = 1;
        dwc_write_reg32( DWC_REG_DAINTMSK, daintmsk.d32 );

        doepmsk.b.setup = 1;
        doepmsk.b.xfercompl = 1;
        doepmsk.b.ahberr = 1;
        doepmsk.b.epdisabled = 1;
        dwc_write_reg32( DWC_REG_DOEPMSK, doepmsk.d32 );

        diepmsk.b.xfercompl = 1;
        diepmsk.b.timeout = 1;
        diepmsk.b.epdisabled = 1;
        diepmsk.b.ahberr = 1;
        dwc_write_reg32( DWC_REG_DIEPMSK, diepmsk.d32 );
        /* Reset Device Address */
        dcfg.d32 = dwc_read_reg32( DWC_REG_DCFG);
        dcfg.b.devaddr = 0;
        dwc_write_reg32( DWC_REG_DCFG, dcfg.d32);

        /* setup EP0 to receive SETUP packets */
        ep0_out_start();

	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.usbreset = 1;
	dwc_write_reg32 ( DWC_REG_GINTSTS, gintsts.d32);

	flush_cpu_cache();
        return 1;
}
Example #16
0
/**
 * This function handles the Rx Status Queue Level Interrupt, which
 * indicates that there is a least one packet in the Rx FIFO.  The
 * packets are moved from the FIFO to memory, where they will be
 * processed when the Endpoint Interrupt Register indicates Transfer
 * Complete or SETUP Phase Done.
 *
 * Repeat the following until the Rx Status Queue is empty:
 *   -#	Read the Receive Status Pop Register (GRXSTSP) to get Packet
 *     	info
 *   -#	If Receive FIFO is empty then skip to step Clear the interrupt
 *     	and exit
 *   -#	If SETUP Packet call dwc_otg_read_setup_packet to copy the
 *   	SETUP data to the buffer
 *   -#	If OUT Data Packet call dwc_otg_read_packet to copy the data
 *     	to the destination buffer
 */
int32_t dwc_otg_pcd_handle_rx_status_q_level_intr()
{
	gintmsk_data_t gintmask = { 0 };
	device_grxsts_data_t status;
	gintsts_data_t gintsts;
	dwc_ep_t *ep;

        
        DBG("dwc_otg_pcd_handle_rx_status_q_level_intr()\n");
        /* Disable the Rx Status Queue Level interrupt */
        gintmask.b.rxstsqlvl= 1;
        dwc_modify_reg32( DWC_REG_GINTMSK, gintmask.d32, 0);

        /* Get the Status from the top of the FIFO */
        status.d32 = dwc_read_reg32( DWC_REG_GRXSTSP);

        //DBG("rx status: ep%d, pktsts: %d\n",status.b.epnum,status.b.pktsts);

        /* Get pointer to EP structure */
	if(status.b.epnum == 0)
	{
		ep = &g_dwc_eps[0];
	}		
	else
	{
		ep = &g_dwc_eps[status.b.epnum];
	}
	 
        switch (status.b.pktsts) {
        case DWC_DSTS_GOUT_NAK:
                DBG( "Global OUT NAK\n");
                break;

        case DWC_STS_DATA_UPDT:
                DBG( "OUT Data Packet\n");
                if (status.b.bcnt && ep->xfer_buff){
                        /** @todo NGS Check for buffer overflow? */
                        dwc_otg_read_packet( ep->xfer_buff,status.b.bcnt);
                        ep->xfer_count += status.b.bcnt;
                        ep->xfer_buff += status.b.bcnt;
                }
                break;

        case DWC_STS_XFER_COMP:
                DBG("OUT Complete\n");
                break;

        case DWC_DSTS_SETUP_COMP:
		   DBG("SETUP Complete\n");
                break;

        case DWC_DSTS_SETUP_UPDT:
		   DBG("SETUP update\n");
                dwc_otg_read_setup_packet( this_pcd.setup_pkt.d32);
		   this_pcd.request_enable = 1;

                ep->xfer_count += status.b.bcnt;
                break;

        default:
                //DBG( "Invalid Packet Status (0x%0x)\n", status.b.pktsts);
                break;
                
        }

        /* Enable the Rx Status Queue Level interrupt */
        dwc_modify_reg32( DWC_REG_GINTMSK, 0, gintmask.d32);
	/* Clear interrupt */
	gintsts.d32 = 0;
	gintsts.b.rxstsqlvl = 1;
	dwc_write_reg32 ( DWC_REG_GINTSTS, gintsts.d32);

        return 1;
}