Example #1
0
/**
 * This function writes a packet into the Tx FIFO associated with the
 * EP.  For non-periodic EPs the non-periodic Tx FIFO is written.  For
 * periodic EPs the periodic Tx FIFO associated with the EP is written
 * with all packets for the next micro-frame.
 *
 * @param _core_if Programming view of DWC_otg controller.
 * @param _ep The EP to write packet for.
 * @param _dma Indicates if DMA is being used.
 */
void dwc_otg_ep_write_packet( dwc_ep_t *_ep)
{
	/**
	 * The buffer is padded to DWORD on a per packet basis in
	 * slave/dma mode if the MPS is not DWORD aligned.  The last
	 * packet, if short, is also padded to a multiple of DWORD.
	 *
	 * ep->xfer_buff always starts DWORD aligned in memory and is a 
	 * multiple of DWORD in length
	 *
	 * ep->xfer_len can be any number of bytes
	 *
	 * ep->xfer_count is a multiple of ep->maxpacket until the last 
	 *  packet
	 *
	 * FIFO access is DWORD */

	uint32_t i;
	uint32_t byte_count;
	uint32_t dword_count;
	uint32_t fifo;
        uint8_t *data_buff = _ep->xfer_buff;
        uint32_t temp_data ;

	//DBG("dwc_otg_ep_write_packet() : %d\n",_ep->xfer_len);
        if (_ep->xfer_count >= _ep->xfer_len) {
                //DWC_WARN("%s() No data for EP%d!!!\n", "dwc_otg_ep_write_packet", _ep->num);
                return;                
        }

	/* Find the byte length of the packet either short packet or MPS */
	if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket) {
		byte_count = _ep->xfer_len - _ep->xfer_count;
	}
	else {
		byte_count = _ep->maxpacket;
	}

	/* Find the DWORD length, padded by extra bytes as neccessary if MPS
	 * is not a multiple of DWORD */
	dword_count =  (byte_count + 3) / 4;


       //fifo = _core_if->data_fifo[_ep->num];
     fifo = DWC_REG_DATA_FIFO(_ep->num);


	for (i=0; i<dword_count; i++) {
		temp_data =get_unaligned(data_buff);
		dwc_write_reg32( fifo, temp_data );
		data_buff += 4;
	}


	_ep->xfer_count += byte_count;
        _ep->xfer_buff += byte_count;

	flush_cpu_cache();

}
Example #2
0
int dwc_pcd_irq()
{
	gintsts_data_t  gintr_status;
	gintsts_data_t  gintr_msk;

	gintr_msk.d32 = dwc_read_reg32(DWC_REG_GINTMSK);
	gintr_status.d32 = dwc_read_reg32(DWC_REG_GINTSTS);
	if((gintr_status.d32 & gintr_msk.d32)== 0)
		return 0;
	
	//DBG("irq gintmsk:  0x%08x\n",gintr_msk.d32);
	//DBG("irq gintrsts: 0x%08x\n",gintr_status.d32);

	gintr_status.d32 = gintr_status.d32 & gintr_msk.d32;
	//DBG("irq gintmsk & gintrsts = 0x%08x\n",gintr_status.d32);

	if (gintr_status.b.rxstsqlvl) {
	    dwc_otg_pcd_handle_rx_status_q_level_intr();
	}
	if (gintr_status.b.nptxfempty) {
	    dwc_otg_pcd_handle_np_tx_fifo_empty_intr( );
	}

	if (gintr_status.b.usbreset) {
	   dwc_otg_pcd_handle_usb_reset_intr( );
	}
	if (gintr_status.b.enumdone) {
	    dwc_otg_pcd_handle_enum_done_intr();
	}
	if (gintr_status.b.epmismatch) {
	    //dwc_otg_pcd_handle_ep_mismatch_intr( core_if );
	}
	if (gintr_status.b.inepint) {
	    dwc_otg_pcd_handle_in_ep_intr();
	}
	if (gintr_status.b.outepintr) {
	    dwc_otg_pcd_handle_out_ep_intr( );
	}

	dwc_write_reg32(DWC_REG_GINTSTS,gintr_status.d32);
	flush_cpu_cache();
	return 0;
}
Example #3
0
/**
 * This function configures EP0 to receive SETUP packets.
 *
 * @todo NGS: Update the comments from the HW FS.
 *
 *  -# 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
 *
 */
static void ep0_out_start(void)
{
	deptsiz0_data_t doeptsize0 = { 0};
	depctl_data_t doepctl = { 0 };

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

	DBG("ep0_out_start()\n");
	dwc_write_reg32( DWC_REG_OUT_EP_TSIZE(0),doeptsize0.d32 );


	// EP enable
	doepctl.d32 = dwc_read_reg32(DWC_REG_OUT_EP_REG(0));
	doepctl.b.epena = 1;

	doepctl.d32 = 0x80008000;
	dwc_write_reg32(DWC_REG_OUT_EP_REG(0),doepctl.d32);

	flush_cpu_cache();
}
static void sync_buf_post_cpu(struct cach_buf *buf,
	enum hwmem_access next_access, struct hwmem_region *next_region)
{
	bool write = next_access & HWMEM_ACCESS_WRITE;
	bool read = next_access & HWMEM_ACCESS_READ;
	struct cach_range region_range;

	if (!write && !read)
		return;

	region_2_range(next_region, buf->size, &region_range);

	if (write) {
		if (speculative_data_prefetch()) {
			/* Defer invalidate */
			struct cach_range intersection;

			intersect_range(&buf->range_in_cpu_cache,
						&region_range, &intersection);

			expand_range(&buf->range_invalid_in_cpu_cache,
								&intersection);

			clean_cpu_cache(buf, &region_range);
		} else {
			flush_cpu_cache(buf, &region_range);
		}
	}
	if (read)
		clean_cpu_cache(buf, &region_range);

	if (buf->in_cpu_write_buf) {
		drain_cpu_write_buf();

		buf->in_cpu_write_buf = false;
	}
}
Example #5
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 #6
0
/**
 * This interrupt occurs when the non-periodic Tx FIFO is half-empty.
 * The active request is checked for the next packet to be loaded into
 * the non-periodic Tx FIFO.
 */
int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(void)
{
        gnptxsts_data_t txstatus = {0};
        gintsts_data_t gintsts;

        int epnum = 0;
        dwc_ep_t *ep = 0;
        uint32_t len = 0;
        int dwords;
	 depctl_data_t depctl;

	DBG("dwc_otg_pcd_handle_np_tx_fifo_empty_intr()\n");
        /* Get the epnum from the IN Token Learning Queue. */
	for (epnum=0; epnum < NUM_EP; epnum++)
	{

		ep = &g_dwc_eps[epnum];


		/* IN endpoint ? */
		if (epnum && !ep->is_in ) {
			continue;
	        }
		depctl.d32 = dwc_read_reg32(DWC_REG_IN_EP_REG(epnum));
	       if (depctl.b.epena != 1)
			continue;

		 if (ep->type == DWC_OTG_EP_TYPE_INTR && ep->xfer_len == 0)
			continue;

		 flush_cpu_cache();

	        len = ep->xfer_len - ep->xfer_count;
	        if (len > ep->maxpacket) {
	                len = ep->maxpacket;
	        }
	        dwords = (len + 3)/4;

		 //DBG("nptx: write data to fifo, ep%d , size %d\n",epnum,len);
	        /* While there is space in the queue and space in the FIFO and
	         * More data to tranfer, Write packets to the Tx FIFO */
	        txstatus.d32 = dwc_read_reg32( DWC_REG_GNPTXSTS );
	        while  (txstatus.b.nptxqspcavail > 0 &&
	                txstatus.b.nptxfspcavail > dwords &&
	                ep->xfer_count < ep->xfer_len) {

			   flush_cpu_cache();

			   /* Write the FIFO */
	                dwc_otg_ep_write_packet( ep );

	                len = ep->xfer_len - ep->xfer_count;
	                if (len > ep->maxpacket) {
	                        len = ep->maxpacket;
	                }
	                dwords = (len + 3)/4;
			   flush_cpu_cache();
			   //txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS);
#if 1
			   /*
				  TODO:  Remove these code.
				  Because, if code break from "while"(Line427), an incomplete-in-trans will occour.
				  Then the tansfer will break.
			   */
			   int retry = 50000;	//retry times
			   while (retry--)
			   {
			       txstatus.d32 = dwc_read_reg32(DWC_REG_GNPTXSTS);
				if(txstatus.b.nptxqspcavail > 0  || //txstatus.b.nptxfspcavail <= dwords ||
					ep->xfer_count >= ep->xfer_len)
					break;
				else
				{
					flush_cpu_cache();
				}

			   }
			   if (retry <= 0)
			   {
				//DWC_ERROR("TxFIFO FULL: Can't trans data to HOST !\n");
			   }

			   /* END todo */
#endif
	        }

	}

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

        return 1;
}
Example #7
0
int dwc_pcd_irq(void)
{
	gintsts_data_t  gintr_status;
	gintsts_data_t  gintr_msk;

	gintr_msk.d32 = dwc_read_reg32(DWC_REG_GINTMSK);
	gintr_status.d32 = dwc_read_reg32(DWC_REG_GINTSTS);

	if ((gintr_status.d32 & gintr_msk.d32)== 0)
		return 0;

	DBG("irq gintmsk:  0x%08x\n",gintr_msk.d32);
	DBG("irq gintrsts: 0x%08x\n",gintr_status.d32);

	gintr_status.d32 = gintr_status.d32 & gintr_msk.d32;
	DBG("irq gintmsk & gintrsts = 0x%08x\n",gintr_status.d32);

    if (gintr_status.b.sofintr)
	{
        if (_sofintr_not_occur) {
			DWN_MSG("sof\n");
			_sofintr_not_occur = 0;
		}
	}

	if (gintr_status.b.rxstsqlvl) {
		dwc_otg_pcd_handle_rx_status_q_level_intr();
		pcd_out_completed(&this_pcd[0]);
	}
	if (gintr_status.b.nptxfempty) {
		dwc_otg_pcd_handle_np_tx_fifo_empty_intr( );
	}

	if (gintr_status.b.usbreset) {
	   dwc_otg_pcd_handle_usb_reset_intr( );
	}
	if (gintr_status.b.enumdone) {
	    dwc_otg_pcd_handle_enum_done_intr();
	}
	if (gintr_status.b.epmismatch) {
	    //dwc_otg_pcd_handle_ep_mismatch_intr( core_if );
	}
	if (gintr_status.b.inepint) {
	    dwc_otg_pcd_handle_in_ep_intr();
	}
	if (gintr_status.b.outepintr) {
	    dwc_otg_pcd_handle_out_ep_intr( );
	}

#if 0
    if (gintr_status.b.otgintr)
    {
        gotgint_data_t gotgint;

        gotgint.d32 = dwc_read_reg32(DWC_REG_GOTGINT);
        if (gotgint.b.sesenddet)
        {
            printf("dis-connect-intr\n");
            cb_4_dis_connect_intr();
        }
    }
#endif//#if 0

    dwc_write_reg32(DWC_REG_GINTSTS,gintr_status.d32);
    flush_cpu_cache();
	return 0;
}
Example #8
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;
}