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

📄 sl811_usb.c

📁 F:worksip2440a board可启动u-boot-like.tar.gz F:worksip2440a board可启动u-boot-like.tar.gz
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * (C) Copyright 2004 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * This code is based on linux driver for sl811hs chip, source at * drivers/usb/host/sl811.c: * * SL811 Host Controller Interface driver for USB. * * Copyright (c) 2003/06, Courage Co., Ltd. * * Based on: *	1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap, *	  Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, *	  Adam Richter, Gregory P. Smith; *	2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com> *	3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn> * * See file CREDITS for list of people who contributed to this * project. * * 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 */#include <common.h>#ifdef CONFIG_USB_SL811HS#include <mpc8xx.h>#include <usb.h>#include "sl811.h"#include "../board/kup/common/kup.h"#ifdef __PPC__# define EIEIO		__asm__ volatile ("eieio")#else# define EIEIO		/* nothing */#endif#define	 SL811_ADR (0x50000000)#define	 SL811_DAT (0x50000001)#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})#ifdef SL811_DEBUGstatic int debug = 9;#endifstatic int root_hub_devnum = 0;static struct usb_port_status rh_status = { 0 };/* root hub port status */static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,			       void *data, int buf_len, struct devrequest *cmd);static void sl811_write (__u8 index, __u8 data){	*(volatile unsigned char *) (SL811_ADR) = index;	EIEIO;	*(volatile unsigned char *) (SL811_DAT) = data;	EIEIO;}static __u8 sl811_read (__u8 index){	__u8 data;	*(volatile unsigned char *) (SL811_ADR) = index;	EIEIO;	data = *(volatile unsigned char *) (SL811_DAT);	EIEIO;	return (data);}/* * Read consecutive bytes of data from the SL811H/SL11H buffer */static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size){	*(volatile unsigned char *) (SL811_ADR) = offset;	EIEIO;	while (size--) {		*buf++ = *(volatile unsigned char *) (SL811_DAT);		EIEIO;	}}/* * Write consecutive bytes of data to the SL811H/SL11H buffer */static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size){	*(volatile unsigned char *) (SL811_ADR) = offset;	EIEIO;	while (size--) {		*(volatile unsigned char *) (SL811_DAT) = *buf++;		EIEIO;	}}int usb_init_kup4x (void){	volatile immap_t *immap = (immap_t *) CFG_IMMR;	volatile memctl8xx_t *memctl = &immap->im_memctl;	int i;	unsigned char tmp;	memctl = &immap->im_memctl;	memctl->memc_or7 = 0xFFFF8726;	memctl->memc_br7 = 0x50000401;	/* start at 0x50000000 */	/* BP 14 low = USB ON */	immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);	/* PB 14 nomal port */	immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);	/* output */	immap->im_cpm.cp_pbdir |= (BP_USB_VCC);	puts ("USB:   ");	for (i = 0x10; i < 0xff; i++) {		sl811_write(i, i);		tmp = (sl811_read(i));		if (tmp != i) {			printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);			return (-1);		}	}	printf ("SL811 ready\n");	return (0);}/* * This function resets SL811HS controller and detects the speed of * the connecting device * * Return: 0 = no device attached; 1 = USB device attached */static int sl811_hc_reset(void){	int status ;	sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);	sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);	mdelay(20);	/* Disable hardware SOF generation, clear all irq status. */	sl811_write(SL811_CTRL1, 0);	mdelay(2);	sl811_write(SL811_INTRSTS, 0xff);	status = sl811_read(SL811_INTRSTS);	if (status & SL811_INTR_NOTPRESENT) {		/* Device is not present */		PDEBUG(0, "Device not present\n");		rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);		rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;		sl811_write(SL811_INTR, SL811_INTR_INSRMV);		return 0;	}	/* Send SOF to address 0, endpoint 0. */	sl811_write(SL811_LEN_B, 0);	sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));	sl811_write(SL811_DEV_B, 0x00);	sl811_write(SL811_SOFLOW, SL811_12M_LOW);	if (status & SL811_INTR_SPEED_FULL) {		/* full speed device connect directly to root hub */		PDEBUG (0, "Full speed Device attached\n");		sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);		mdelay(20);		sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);		sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);		/* start the SOF or EOP */		sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);		rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;		rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;		mdelay(2);		sl811_write(SL811_INTRSTS, 0xff);	} else {		/* slow speed device connect directly to root-hub */		PDEBUG(0, "Low speed Device attached\n");		sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);		mdelay(20);		sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);		sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);		/* start the SOF or EOP */		sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);		rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;		mdelay(2);		sl811_write(SL811_INTRSTS, 0xff);	}	rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;	sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);	return 1;}int usb_lowlevel_init(void){	root_hub_devnum = 0;	sl811_hc_reset();	return 0;}int usb_lowlevel_stop(void){	sl811_hc_reset();	return 0;}static int calc_needed_buswidth(int bytes, int need_preamble){	return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;}static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len){	__u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;	__u16 status = 0;	int err = 0, time_start = get_timer(0);	int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&		usb_pipeslow(pipe);	if (len > 239)		return -1;	if (usb_pipeout(pipe))		ctrl |= SL811_USB_CTRL_DIR_OUT;	if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))		ctrl |= SL811_USB_CTRL_TOGGLE_1;	if (need_preamble)		ctrl |= SL811_USB_CTRL_PREAMBLE;	sl811_write(SL811_INTRSTS, 0xff);	while (err < 3) {		sl811_write(SL811_ADDR_A, 0x10);		sl811_write(SL811_LEN_A, len);		if (usb_pipeout(pipe) && len)			sl811_write_buf(0x10, buffer, len);		if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&		    sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))			ctrl |= SL811_USB_CTRL_SOF;		else			ctrl &= ~SL811_USB_CTRL_SOF;		sl811_write(SL811_CTRL_A, ctrl); 		while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {			if (5*CFG_HZ < get_timer(time_start)) {				printf("USB transmit timed out\n");				return -USB_ST_CRC_ERR;			}		}		sl811_write(SL811_INTRSTS, 0xff);		status = sl811_read(SL811_STS_A);		if (status & SL811_USB_STS_ACK) {			int remainder = sl811_read(SL811_CNT_A);			if (remainder) {				PDEBUG(0, "usb transfer remainder = %d\n", remainder);				len -= remainder;			}			if (usb_pipein(pipe) && len)				sl811_read_buf(0x10, buffer, len);			return len;		}		if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)			continue;		PDEBUG(0, "usb transfer error %#x\n", (int)status);		err++;	}	err = 0;	if (status & SL811_USB_STS_ERROR)		err |= USB_ST_BUF_ERR;	if (status & SL811_USB_STS_TIMEOUT)		err |= USB_ST_CRC_ERR;	if (status & SL811_USB_STS_STALL)		err |= USB_ST_STALLED;	return -err;}int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,		    int len){	int dir_out = usb_pipeout(pipe);	int ep = usb_pipeendpoint(pipe);	int max = usb_maxpacket(dev, pipe);	int done = 0;	PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",	       usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);	dev->status = 0;	sl811_write(SL811_DEV_A, usb_pipedevice(pipe));	sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));	while (done < len) {		int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,					    max > len - done ? len - done : max);		if (res < 0) {			dev->status = -res;			return res;		}		if (!dir_out && res < max) /* short packet */			break;		done += res;		usb_dotoggle(dev, ep, dir_out);	}	dev->act_len = done;	return 0;}int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,		       int len,struct devrequest *setup){	int done = 0;	int devnum = usb_pipedevice(pipe);	int ep = usb_pipeendpoint(pipe);	dev->status = 0;	if (devnum == root_hub_devnum)		return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);	PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",	       devnum, ep, buffer, len, (int)setup->requesttype,	       (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);	sl811_write(SL811_DEV_A, devnum);	sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));	/* setup phase */	usb_settoggle(dev, ep, 1, 0);	if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),			      (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {		int dir_in = usb_pipein(pipe);		int max = usb_maxpacket(dev, pipe);		/* data phase */		sl811_write(SL811_PIDEP_A,			    PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));

⌨️ 快捷键说明

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