⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbdcore_mpc8xx.c

📁 U-boot源码 ARM7启动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit * bodonoghue@CodeHermit.ie * * References * DasUBoot/drivers/usbdcore_omap1510.c, for design and implementation ideas. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. * *//* * Notes : * 1.	#define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX *		packet to force the USB re-transmit protocol. * * 2.	#define __DEBUG_UDC__ to switch on debug tracing to serial console *	be careful that tracing doesn't create Hiesen-bugs with respect to *	response timeouts to control requests. * * 3.	This driver should be able to support any higher level driver that *	that wants to do either of the two standard UDC implementations *	Control-Bulk-Interrupt or  Bulk-IN/Bulk-Out standards. Hence *	gserial and cdc_acm should work with this code. * * 4.	NAK events never actually get raised at all, the documentation *	is just wrong ! * * 5.	For some reason, cbd_datlen is *always* +2 the value it should be. *	this means that having an RX cbd of 16 bytes is not possible, since *	the same size is reported for 14 bytes received as 16 bytes received *	until we can find out why this happens, RX cbds must be limited to 8 *	bytes. TODO: check errata for this behaviour. * * 6.	Right now this code doesn't support properly powering up with the USB *	cable attached to the USB host my development board the Adder87x doesn't *	have a pull-up fitted to allow this, so it is necessary to power the *	board and *then* attached the USB cable to the host. However somebody *	with a different design in their board may be able to keep the cable *	constantly connected and simply enable/disable a pull-up  re *	figure 31.1 in MPC885RM.pdf instead of having to power up the board and *	then attach the cable ! * */#include <common.h>#include <config.h>#if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE)#include <commproc.h>#include "usbdcore.h"#include "usbdcore_mpc8xx.h"#include "usbdcore_ep0.h"DECLARE_GLOBAL_DATA_PTR;#define ERR(fmt, args...)\	serial_printf("ERROR : [%s] %s:%d: "fmt,\				__FILE__,__FUNCTION__,__LINE__, ##args)#ifdef __DEBUG_UDC__#define DBG(fmt,args...)\		serial_printf("[%s] %s:%d: "fmt,\				__FILE__,__FUNCTION__,__LINE__, ##args)#else#define DBG(fmt,args...)#endif/* Static Data */#ifdef __SIMULATE_ERROR__static char err_poison_test = 0;#endifstatic struct mpc8xx_ep ep_ref[MAX_ENDPOINTS];static u32 address_base = STATE_NOT_READY;static mpc8xx_udc_state_t udc_state = 0;static struct usb_device_instance *udc_device = 0;static volatile usb_epb_t *endpoints[MAX_ENDPOINTS];static volatile cbd_t *tx_cbd[TX_RING_SIZE];static volatile cbd_t *rx_cbd[RX_RING_SIZE];static volatile immap_t *immr = 0;static volatile cpm8xx_t *cp = 0;static volatile usb_pram_t *usb_paramp = 0;static volatile usb_t *usbp = 0;static int rx_ct = 0;static int tx_ct = 0;/* Static Function Declarations */static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,					    usb_device_state_t final);static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,					      usb_device_state_t final);static void mpc8xx_udc_stall (unsigned int ep);static void mpc8xx_udc_flush_tx_fifo (int epid);static void mpc8xx_udc_flush_rx_fifo (void);static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp);static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi,				struct urb *tx_urb);static void mpc8xx_udc_dump_request (struct usb_device_request *request);static void mpc8xx_udc_clock_init (volatile immap_t * immr,				   volatile cpm8xx_t * cp);static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi);static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp);static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp);static void mpc8xx_udc_cbd_init (void);static void mpc8xx_udc_endpoint_init (void);static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size);static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment);static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp);static void mpc8xx_udc_set_nak (unsigned int ep);static short mpc8xx_udc_handle_txerr (void);static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid);/******************************************************************************			       Global Linkage *****************************************************************************//* udc_init * * Do initial bus gluing */int udc_init (void){	/* Init various pointers */	immr = (immap_t *) CFG_IMMR;	cp = (cpm8xx_t *) & (immr->im_cpm);	usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]);	usbp = (usb_t *) & (cp->cp_scc[0]);	memset (ep_ref, 0x00, (sizeof (struct mpc8xx_ep) * MAX_ENDPOINTS));	udc_device = 0;	udc_state = STATE_NOT_READY;	usbp->usmod = 0x00;	usbp->uscom = 0;	/* Set USB Frame #0, Respond at Address & Get a clock source  */	usbp->usaddr = 0x00;	mpc8xx_udc_clock_init (immr, cp);	/* PA15, PA14 as perhiperal USBRXD and USBOE */	immr->im_ioport.iop_padir &= ~0x0003;	immr->im_ioport.iop_papar |= 0x0003;	/* PC11/PC10 as peripheral USBRXP USBRXN */	immr->im_ioport.iop_pcso |= 0x0030;	/* PC7/PC6 as perhiperal USBTXP and USBTXN */	immr->im_ioport.iop_pcdir |= 0x0300;	immr->im_ioport.iop_pcpar |= 0x0300;	/* Set the base address */	address_base = (u32) (cp->cp_dpmem + CPM_USB_BASE);	/* Initialise endpoints and circular buffers */	mpc8xx_udc_endpoint_init ();	mpc8xx_udc_cbd_init ();	/* Assign allocated Dual Port Endpoint descriptors */	usb_paramp->ep0ptr = (u32) endpoints[0];	usb_paramp->ep1ptr = (u32) endpoints[1];	usb_paramp->ep2ptr = (u32) endpoints[2];	usb_paramp->ep3ptr = (u32) endpoints[3];	usb_paramp->frame_n = 0;	DBG ("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n",	     usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr,	     usb_paramp->ep3ptr);	return 0;}/* udc_irq * * Poll for whatever events may have occured */void udc_irq (void){	int epid = 0;	volatile cbd_t *rx_cbdp = 0;	volatile cbd_t *rx_cbdp_base = 0;	if (udc_state != STATE_READY) {		return;	}	if (usbp->usber & USB_E_BSY) {		/* This shouldn't happen. If it does then it's a bug ! */		usbp->usber |= USB_E_BSY;		mpc8xx_udc_flush_rx_fifo ();	}	/* Scan all RX/Bidirectional Endpoints for RX data. */	for (epid = 0; epid < MAX_ENDPOINTS; epid++) {		if (!ep_ref[epid].prx) {			continue;		}		rx_cbdp = rx_cbdp_base = ep_ref[epid].prx;		do {			if (!(rx_cbdp->cbd_sc & RX_BD_E)) {				if (rx_cbdp->cbd_sc & 0x1F) {					/* Corrupt data discard it.					 * Controller has NAK'd this packet.					 */					mpc8xx_udc_clear_rxbd (rx_cbdp);				} else {					if (!epid) {						mpc8xx_udc_ep0_rx (rx_cbdp);					} else {						/* Process data */						mpc8xx_udc_set_nak (epid);						mpc8xx_udc_epn_rx (epid, rx_cbdp);						mpc8xx_udc_clear_rxbd (rx_cbdp);					}				}				/* Advance RX CBD pointer */				mpc8xx_udc_advance_rx (&rx_cbdp, epid);				ep_ref[epid].prx = rx_cbdp;			} else {				/* Advance RX CBD pointer */				mpc8xx_udc_advance_rx (&rx_cbdp, epid);			}		} while (rx_cbdp != rx_cbdp_base);	}	/* Handle TX events as appropiate, the correct place to do this is	 * in a tx routine. Perhaps TX on epn was pre-empted by ep0	 */	if (usbp->usber & USB_E_TXB) {		usbp->usber |= USB_E_TXB;	}	if (usbp->usber & (USB_TX_ERRMASK)) {		mpc8xx_udc_handle_txerr ();	}	/* Switch to the default state, respond at the default address */	if (usbp->usber & USB_E_RESET) {		usbp->usber |= USB_E_RESET;		usbp->usaddr = 0x00;		udc_device->device_state = STATE_DEFAULT;	}	/* if(usbp->usber&USB_E_IDLE){	   We could suspend here !	   usbp->usber|=USB_E_IDLE;	   DBG("idle state change\n");	   }	   if(usbp->usbs){	   We could resume here when IDLE is deasserted !	   Not worth doing, so long as we are self powered though.	   }	*/	return;}/* udc_endpoint_write * * Write some data to an endpoint */int udc_endpoint_write (struct usb_endpoint_instance *epi){	int ep = 0;	short epid = 1, unnak = 0, ret = 0;	if (udc_state != STATE_READY) {		ERR ("invalid udc_state != STATE_READY!\n");		return -1;	}	if (!udc_device || !epi) {		return -1;	}	if (udc_device->device_state != STATE_CONFIGURED) {		return -1;	}	ep = epi->endpoint_address & 0x03;	if (ep >= MAX_ENDPOINTS) {		return -1;	}	/* Set NAK for all RX endpoints during TX */	for (epid = 1; epid < MAX_ENDPOINTS; epid++) {		/* Don't set NAK on DATA IN/CONTROL endpoints */		if (ep_ref[epid].sc & USB_DIR_IN) {			continue;		}		if (!(usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK))) {			unnak |= 1 << epid;		}		mpc8xx_udc_set_nak (epid);	}	mpc8xx_udc_init_tx (&udc_device->bus->endpoint_array[ep],			    epi->tx_urb);	ret = mpc8xx_udc_ep_tx (&udc_device->bus->endpoint_array[ep]);	/* Remove temporary NAK */	for (epid = 1; epid < MAX_ENDPOINTS; epid++) {		if (unnak & (1 << epid)) {			udc_unset_nak (epid);		}	}	return ret;}/* mpc8xx_udc_assign_urb * * Associate a given urb to an endpoint TX or RX transmit/receive buffers */static int mpc8xx_udc_assign_urb (int ep, char direction){	struct usb_endpoint_instance *epi = 0;	if (ep >= MAX_ENDPOINTS) {		goto err;	}	epi = &udc_device->bus->endpoint_array[ep];	if (!epi) {		goto err;	}	if (!ep_ref[ep].urb) {		ep_ref[ep].urb = usbd_alloc_urb (udc_device, udc_device->bus->endpoint_array);		if (!ep_ref[ep].urb) {			goto err;		}	} else {		ep_ref[ep].urb->actual_length = 0;	}	switch (direction) {	case USB_DIR_IN:		epi->tx_urb = ep_ref[ep].urb;		break;	case USB_DIR_OUT:		epi->rcv_urb = ep_ref[ep].urb;		break;	default:		goto err;	}	return 0;      err:	udc_state = STATE_ERROR;	return -1;}/* udc_setup_ep * * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram * Isochronous endpoints aren't yet supported! */void udc_setup_ep (struct usb_device_instance *device, unsigned int ep,		   struct usb_endpoint_instance *epi){	uchar direction = 0;	int ep_attrib = 0;	if (epi && (ep < MAX_ENDPOINTS)) {		if (ep == 0) {			if (epi->rcv_attributes != USB_ENDPOINT_XFER_CONTROL			    || epi->tx_attributes !=			    USB_ENDPOINT_XFER_CONTROL) {				/* ep0 must be a control endpoint */				udc_state = STATE_ERROR;				return;			}			if (!(ep_ref[ep].sc & EP_ATTACHED)) {				mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize,						       epi->rcv_packetSize);			}			usbp->usep[ep] = 0x0000;			return;		}		if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK)		    == USB_DIR_IN) {			direction = 1;			ep_attrib = epi->tx_attributes;			epi->rcv_packetSize = 0;			ep_ref[ep].sc |= USB_DIR_IN;		} else {			direction = 0;			ep_attrib = epi->rcv_attributes;			epi->tx_packetSize = 0;			ep_ref[ep].sc &= ~USB_DIR_IN;		}		if (mpc8xx_udc_assign_urb (ep, epi->endpoint_address					   & USB_ENDPOINT_DIR_MASK)) {			return;		}		switch (ep_attrib) {		case USB_ENDPOINT_XFER_CONTROL:			if (!(ep_ref[ep].sc & EP_ATTACHED)) {				mpc8xx_udc_cbd_attach (ep,						       epi->tx_packetSize,						       epi->rcv_packetSize);			}			usbp->usep[ep] = ep << 12;			epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb;			break;		case USB_ENDPOINT_XFER_BULK:		case USB_ENDPOINT_XFER_INT:			if (!(ep_ref[ep].sc & EP_ATTACHED)) {				if (direction) {					mpc8xx_udc_cbd_attach (ep,							       epi->tx_packetSize,							       0);				} else {					mpc8xx_udc_cbd_attach (ep,							       0,							       epi->rcv_packetSize);				}			}			usbp->usep[ep] = (ep << 12) | ((ep_attrib) << 8);			break;		case USB_ENDPOINT_XFER_ISOC:		default:			serial_printf ("Error endpoint attrib %d>3\n", ep_attrib);			udc_state = STATE_ERROR;			break;		}	}}/* udc_connect * * Move state, switch on the USB */void udc_connect (void){	/* Enable pull-up resistor on D+

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -