LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Accessing the CPM2 on an MPC82xx : CPM_MAP_ADDR or cpm2_immr ?
From: Dan Malek @ 2006-02-02 18:55 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linuxppc-embedded
In-Reply-To: <200602021642.49282.laurent.pinchart@tbox.biz>


On Feb 2, 2006, at 10:42 AM, Laurent Pinchart wrote:

> The new fs_enet driver internally maps CPM_MAP_ADDR. Should every 
> driver
> create an internal CPM mapping ?

Yes, they should.  All drivers should do the ioremap() and stash the
pointer internally.

> .... Why was the old fec_enet driver able to
> access the CPM through CPM_MAP_ADDR without ioremap()ing it first ?

Because that's a long left over "performance hack" from many
years ago when I first implemented the 8xx software.  The IMMR used
to be mapped to a well known virtual address, the board initialization
did this early, and everyone (ab)used it.  This was way back in the 
2.0/2.1
days when it was acceptable to do such things :-)  Due to the CPM2 now
being used on may different Freescale parts, and mapped in various
ways, the internal mapping should be done by every driver.

Thanks.

	-- Dan

^ permalink raw reply

* Re: AW: MPC5200,PSC in uart mode, receiving problem
From: Frank Bodammer @ 2006-02-02 18:22 UTC (permalink / raw)
  To: Linuxppc-Embedded
In-Reply-To: <002001c5ce3b$3972bbe0$34f1ff0a@beint.local>

[-- Attachment #1: Type: text/plain, Size: 1145 bytes --]

Achim Machura wrote:
> Here the patch
>  
> 
>>Even better, post a patch here on the list so we all can benefit.

I experienced similar problems with the serial ports on mpc5200 PSCs
and so i was happy to find your patch, which solved some problem, but
not all. The overrun flag still wasn´t reset after an input overrun
error, so this error was reported persistent for each received character.
I fixed this by adding an command to reset the psc error flags in
receive_char() where the overrun flag is checked. Maybe this isn't
the best solution, but it seems to work.

To reset the overrun error flag, i tried the following statement:

	out_8(&psc->command, MPC5xxx_PSC_RST_ERR_STAT);

but i got unpredictable behaviour in some cases ending in a reset.
Doing the same this way:

	psc->command = MPC5xxx_PSC_RST_ERR_STAT;

always worked as expected. Does someone know what may be wrong with
'out_8' on mpc5200 with kernel 2.4.25 or is that a configuration problem.

By the way, i improved some other parts of the code, especially the
/proc output and the portconfig stuff, so i also attach a patch here,
even not all of it may be useful.

Frank

[-- Attachment #2: patch_linuxppc_2_4_psc-060202.diff --]
[-- Type: text/plain, Size: 18129 bytes --]

--- psc-orig.c	2006-02-02 10:41:45.000000000 +0100
+++ psc.c	2006-02-02 17:30:59.000000000 +0100
@@ -29,6 +29,7 @@
 #include <linux/serial.h>
 #include <linux/serialP.h>
 #include <linux/generic_serial.h>
+#include <linux/proc_fs.h>
 #ifdef CONFIG_UBOOT
 #include <asm/ppcboot.h>
 #endif
@@ -37,7 +38,8 @@
  * This driver can spew a whole lot of debugging output at you. If you
  * need maximum performance, you should disable the DEBUG define.
  */
-#undef MPC5xxx_PSC_DEBUG 
+#undef MPC5xxx_PSC_DEBUG
+//#define MPC5xxx_PSC_DEBUG		1
 
 #ifdef MPC5xxx_PSC_DEBUG
 #define MPC5xxx_PSC_DEBUG_OPEN		0x00000001
@@ -55,6 +57,7 @@
 #define MPC5xxx_PSC_DEBUG_FIRMWARE	0x00001000
 #define MPC5xxx_PSC_DEBUG_MEMTEST	0x00002000
 #define MPC5xxx_PSC_DEBUG_THROTTLE	0x00004000
+#define MPC5xxx_PSC_DEBUG_CLEARERR	0x00008000
 #define MPC5xxx_PSC_DEBUG_ALL		0xffffffff
 
 int rs_debug = MPC5xxx_PSC_DEBUG_ALL & ~MPC5xxx_PSC_DEBUG_TRANSMIT;
@@ -73,7 +76,7 @@
 /*
  * Number of serial ports
  */
-#define MPC5xxx_PSC_NPORTS	3
+#define MPC5xxx_PSC_NPORTS	4
 
 #ifdef CONFIG_PPC_5xxx_PSC_CONSOLE
 #ifndef CONFIG_PPC_5xxx_PSC_CONSOLE_PORT
@@ -89,7 +92,7 @@
 /*
  * Hardware specific serial port structure
  */
-struct rs_port { 	
+struct rs_port {
 	struct gs_port		gs;		/* Must be first field! */
 
 	struct mpc5xxx_psc	*psc;
@@ -121,7 +124,7 @@
 /*
  * Used by generic serial driver to access hardware
  */
-static struct real_driver rs_real_driver = { 
+static struct real_driver rs_real_driver = {
 	.disable_tx_interrupts	= rs_disable_tx_interrupts, 
 	.enable_tx_interrupts	= rs_enable_tx_interrupts, 
 	.disable_rx_interrupts	= rs_disable_rx_interrupts, 
@@ -134,9 +137,15 @@
 	.hungup			= rs_hungup,
 }; 
 
+#ifdef CONFIG_PS2MULT
+struct serial_state rs_table[RS_TABLE_SIZE] = {
+	SERIAL_PORT_DFNS	/* Defined in serial.h */
+};
+#else
 static struct serial_state rs_table[RS_TABLE_SIZE] = {
 	SERIAL_PORT_DFNS	/* Defined in serial.h */
 };
+#endif
 
 /*
  * Structures and such for TTY sessions and usage counts
@@ -151,6 +160,14 @@
 int rs_initialized = 0;
 
 /*
+ * proc stuff
+ */
+static int sio_read_info(char * buf, char ** start, off_t offset, int count, int  *eof, void * data);
+
+static struct proc_dir_entry 	*proc_psc_dir,
+				*proc_psc[MPC5xxx_PSC_NPORTS];
+
+/*
  * ----------------------------------------------------------------------
  *
  * Here starts the interrupt handling routines.  All of the following
@@ -180,11 +197,11 @@
 
 	/* While there are characters, get them ... */
 	while (--count >= 0) {
-		status = in_be16(&psc->mpc5xxx_psc_status);
+		status = psc->mpc5xxx_psc_status;
 		if (!(status & MPC5xxx_PSC_SR_RXRDY))
 			break;
 
-		ch = in_8(&psc->mpc5xxx_psc_buffer_8);
+		ch = psc->mpc5xxx_psc_buffer_8;
 
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
 			continue;
@@ -215,6 +232,9 @@
 					tty->flip.count++;
 				}
 				*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+				rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE, "reset psc overrun error status: 0x%04x\n", status);
+				/* Reset PSC error status */
+				psc->command = MPC5xxx_PSC_RST_ERR_STAT;
 			}
 		}
 
@@ -234,7 +254,7 @@
 
 	/* While I'm able to transmit ... */
 	while (--count >= 0) {
-		status = in_be16(&psc->mpc5xxx_psc_status);
+		status = psc->mpc5xxx_psc_status;
 		/*
 		 * XXX -df
 		 * check_modem_status(status);
@@ -243,7 +263,7 @@
 			break;
 
 		if (port->x_char) {
-			out_8(&psc->mpc5xxx_psc_buffer_8, port->x_char);
+			psc->mpc5xxx_psc_buffer_8 = port->x_char;
 			port->icount.tx++;
 			port->x_char = 0;
 		}
@@ -252,8 +272,7 @@
 			break;
 		}
 		else {
-			out_8(&psc->mpc5xxx_psc_buffer_8,
-				port->gs.xmit_buf[port->gs.xmit_tail++]);
+			psc->mpc5xxx_psc_buffer_8 = port->gs.xmit_buf[port->gs.xmit_tail++];
 			port->icount.tx++;
 			port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1;
 			if (--port->gs.xmit_cnt <= 0) {
@@ -266,7 +285,7 @@
 			 port->gs.tty->hw_stopped) {
 		rs_disable_tx_interrupts(port);
 	}
-	
+
 	if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
 		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 				port->gs.tty->ldisc.write_wakeup)
@@ -275,7 +294,7 @@
 				"Waking up.... ldisc (%d)....\n",
 				port->gs.wakeup_chars); 
 		wake_up_interruptible(&port->gs.tty->write_wait);
-	}	
+	}
 }
 
 
@@ -294,19 +313,35 @@
 
 static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct rs_port * port;
+	struct rs_port * port = (struct rs_port *)dev_id;
+	struct mpc5xxx_psc *psc = port->psc;
 	unsigned long flags;
+	u16 status;
 
 	spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
 
-	port = (struct rs_port *)dev_id;
 	rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS,
 			"rs_interrupt (port %p)...", port);
 
+	if (!port || !port->gs.tty) {
+		printk( KERN_DEBUG"%s(%d): port=%p tty=%p\n", __FUNCTION__, __LINE__,
+				port, port?port->gs.tty:NULL );
+		goto out;
+	}
+
+	status = psc->mpc5xxx_psc_status;
+	/* RB-Bit is set ?  */
+	if (status & MPC5xxx_PSC_SR_RB)
+	{
+		rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS, "reset psc error status: 0x%04x\n", status);
+		psc->command = MPC5xxx_PSC_RST_ERR_STAT;
+		goto out;
+	}
+
 	receive_char(port);
 
 	transmit_char(port);
-
+out:
 	spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
 
 	rs_dprintk(MPC5xxx_PSC_DEBUG_INTERRUPTS, "end.\n");
@@ -318,7 +353,7 @@
  *		interface with the generic_serial driver		*
  ************************************************************************
  */
-static void rs_disable_tx_interrupts(void * ptr) 
+static void rs_disable_tx_interrupts(void *ptr)
 {
 	struct rs_port *port = ptr; 
 	struct mpc5xxx_psc *psc = port->psc;
@@ -328,7 +363,7 @@
 	port->gs.flags &= ~GS_TX_INTEN;
 
 	port->imr &= ~MPC5xxx_PSC_IMR_TXRDY;
-	out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+	psc->mpc5xxx_psc_imr = port->imr;
 
 	spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
 }
@@ -342,7 +377,7 @@
 	spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
 
 	port->imr |= MPC5xxx_PSC_IMR_TXRDY;
-	out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+	psc->mpc5xxx_psc_imr = port->imr;
 
 	/* Send a char to start TX interrupts happening */
 	transmit_char(port);
@@ -359,7 +394,8 @@
 	spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
 
 	port->imr &= ~MPC5xxx_PSC_IMR_RXRDY;
-	out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+	psc->mpc5xxx_psc_imr = port->imr;
+	rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE,"disable RxInt\n");
 
 	spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
 }
@@ -373,18 +409,10 @@
 	spin_lock_irqsave(&mpc5xxx_serial_lock, flags);
 
 	port->imr |= MPC5xxx_PSC_IMR_RXRDY;
-	out_be16(&psc->mpc5xxx_psc_imr, port->imr);
-
-	/* Empty the input buffer - apparently this is *vital* */
-	/*
-	 * XXXX add this back in if needed, -df
-	 *
-	 * while (in_be16(&psc->mpc5xxx_psc_status) & MPC5xxx_PSC_SR_RXRDY)
-	 *	in_8(&psc->mpc5xxx_psc_buffer_8);
-	 */
+	psc->mpc5xxx_psc_imr = port->imr;
+	rs_dprintk(MPC5xxx_PSC_DEBUG_RECEIVE,"enable RxInt\n");
 
 	spin_unlock_irqrestore(&mpc5xxx_serial_lock, flags);
-
 }
 
 static int rs_get_CD(void * ptr) 
@@ -394,7 +422,7 @@
 	func_enter();
 
 	func_exit();
-	return (in_8(&port->psc->mpc5xxx_psc_ipcr) & MPC5xxx_PSC_DCD) != 0;
+	return (port->psc->mpc5xxx_psc_ipcr & MPC5xxx_PSC_DCD) != 0;
 }
 
 static void rs_shutdown_port(void * ptr) 
@@ -432,34 +460,67 @@
 
 	divisor = ((port->gs.baud_base / (port->gs.baud * 16)) + 1) >> 1;
 	if (port->gs.baud < 50 || divisor == 0) {
-		printk(KERN_NOTICE "MPC5xxx PSC: Bad speed requested, %d\n",
-				port->gs.baud);
+		printk(KERN_NOTICE "MPC5xxx PSC: Bad speed requested, %d, %d\n",
+				port->gs.baud, divisor);
 		return 0;
 	}
 	/* Configure the PSC for UART mode */
 	line = minor(port->gs.tty->device) - port->gs.tty->driver.minor_start;
+
+#if 0
+	/* This works only for PSC1..PSC3 and assumes that the ports are assigned  */
+	/* in this order. In other configurations it affects functions like usb    */
+	/* or ethernet. It isn't needed, when portconfig is done by the bootloader */
 	val32 = in_be32(&gpio->port_config);
 	val32 |= (MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD << (4*line));
 	out_be32(&gpio->port_config, val32);
+#else
+	switch ((int) port->psc) {
+		case MPC5xxx_PSC1: {
+			rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC1\n");
+			gpio->port_config |= MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD;
+			break;
+		}
+		case MPC5xxx_PSC2: {
+			rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC2\n");
+			gpio->port_config |= (MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD << 4);
+			break;
+		}
+		case MPC5xxx_PSC3: {
+			rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC3\n");
+			gpio->port_config |= (MPC5xxx_GPIO_PSC_CONFIG_UART_WITHOUT_CD << 8);
+			break;
+		}
+		case MPC5xxx_PSC4: {
+			rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC4\n");
+			break;
+		}
+		case MPC5xxx_PSC5: {
+			rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC5\n");
+			break;
+		}
+		case MPC5xxx_PSC6: {
+			rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "Setup portconfig for PSC6\n");
+			break;
+		}
+	}
+#endif
+
 	/* reset and enable PSC */
-	out_8(&psc->command, MPC5xxx_PSC_RST_TX
-		  | MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE);
-	out_8(&psc->command, MPC5xxx_PSC_RST_RX);
+	psc->command = MPC5xxx_PSC_RST_TX | MPC5xxx_PSC_TX_ENABLE;
+
 	/* Set PSC operation mode as 'UART, DCD ignored' */
-	out_be32(&psc->sicr, 0x0);
+	psc->sicr = 0x0;
 	/* Set clocking */
-	out_be16(&psc->mpc5xxx_psc_clock_select, 0xdd00);
+	psc->mpc5xxx_psc_clock_select = 0xdd00;
 	/* Set tx FIFO alarm level */
-	out_be16(&psc->tfalarm, 0xf8);
+	psc->tfalarm = 0xf8;
 	/* Put PSC into the operation */
-	out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1
-		  | MPC5xxx_PSC_RX_ENABLE
-		  | MPC5xxx_PSC_TX_ENABLE);
-
-	rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "calculated divisor: %d\n",
-			divisor);
-	out_8(&psc->ctur, divisor>>8);
-	out_8(&psc->ctlr, divisor);
+	psc->command = MPC5xxx_PSC_SEL_MODE_REG_1 | MPC5xxx_PSC_RX_ENABLE | MPC5xxx_PSC_TX_ENABLE;
+
+	rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS, "calculated divisor: %d\n", divisor);
+	psc->ctur = divisor >> 8;
+	psc->ctlr = divisor;
 
 	/* Program hardware for parity, data bits, stop bits */
 	if ((CFLAG & CSIZE)==CS5)
@@ -496,19 +557,20 @@
 	rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS,
 			"baud_base: %d\n", port->gs.baud_base);
 #ifdef MPC5xxx_PSC_DEBUG
-	if (rs_debug & MPC5xxx_PSC_DEBUG_TERMIOS)
-		out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1);
+	if (rs_debug & MPC5xxx_PSC_DEBUG_TERMIOS) {
+		psc->command = MPC5xxx_PSC_SEL_MODE_REG_1;
+	}
 #endif
 	rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS,
 			"mode 1 register was: %08x, now: %08x\n",
-			in_8(&psc->mode), mode1);
+			psc->mode, mode1);
 	rs_dprintk(MPC5xxx_PSC_DEBUG_TERMIOS,
 			"mode 2 register was: %08x, now: %08x\n",
-			in_8(&psc->mode), mode2);
+			psc->mode, mode2);
 
-	out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1);
-	out_8(&psc->mode, mode1);
-	out_8(&psc->mode, mode2);
+	psc->command = MPC5xxx_PSC_SEL_MODE_REG_1;
+	psc->mode = mode1;
+	psc->mode = mode2;
 
 	func_exit();
 	return 0;
@@ -539,7 +601,7 @@
 
 	line = minor(tty->device) - tty->driver.minor_start;
 	rs_dprintk(MPC5xxx_PSC_DEBUG_OPEN,
-			"%d: opening line %d. tty=%p ctty=%p)\n", 
+			"%d: opening line %d. tty=%p ctty=%p)\n",
 			(int) current->pid, line, tty, current->tty);
 
 	if ((line < 0) || (line >= RS_TABLE_SIZE))
@@ -728,7 +790,7 @@
 #endif
 
 	func_enter();
-	
+
 	if (I_IXOFF(tty)) {
 		if (port->x_char)
 			port->x_char = 0;
@@ -763,6 +825,7 @@
 static int rs_init_portstructs(void)
 {
 	struct rs_port *port;
+	struct mpc5xxx_psc *psc;
 	int i;
 #ifdef CONFIG_UBOOT
 	extern unsigned char __res[];
@@ -789,7 +852,7 @@
 	rs_driver.termios_locked = rs_termios_locked;
 
 	port = rs_ports;
-	for (i=0; i < MPC5xxx_PSC_NPORTS;i++) {
+	for (i = 0; i < MPC5xxx_PSC_NPORTS; i++) {
 		rs_dprintk(MPC5xxx_PSC_DEBUG_INIT, "initing port %d\n", i);
 		port->gs.callout_termios = tty_std_termios;
 		port->gs.normal_termios	= tty_std_termios;
@@ -813,6 +876,8 @@
 #endif
 		rs_dprintk(MPC5xxx_PSC_DEBUG_INIT, "psc base 0x%08lx\n",
 				(unsigned long)port->psc);
+		psc = port->psc;
+		psc->command = MPC5xxx_PSC_RST_ERR_STAT;
 		port++;
 	}
 
@@ -822,7 +887,9 @@
 
 static int rs_init_drivers(void)
 {
-	int error;
+	struct rs_port *port;
+	char proc_psc_name[8];
+	int i, error;
 
 	func_enter();
 
@@ -878,6 +945,19 @@
 		return 1;
 	}
 
+	/* Create /proc entries */
+	proc_psc_dir = proc_mkdir("driver/psc_mpc52xx", NULL);
+	if (proc_psc_dir != NULL) {
+		for (i=0; i < MPC5xxx_PSC_NPORTS; i++) {
+			sprintf(proc_psc_name, "ttyS%1d", i);
+			proc_psc[i] = create_proc_entry(proc_psc_name, 0444, proc_psc_dir);
+			proc_psc[i]->read_proc = sio_read_info;
+			proc_psc[i]->write_proc = NULL;
+			proc_psc[i]->data = &rs_ports[i];
+			proc_psc[i]->owner = THIS_MODULE;
+		}
+	}
+
 	func_exit();
 	return 0;
 }
@@ -888,6 +968,7 @@
 	int rc;
 	int i;
 	struct rs_port *port;
+	char name[6];
 
 	func_enter();
 	rs_dprintk(MPC5xxx_PSC_DEBUG_INIT,
@@ -896,20 +977,29 @@
 	rc = rs_init_portstructs();
 	rs_init_drivers();
 	port = rs_ports;
-	for (i=0; i < MPC5xxx_PSC_NPORTS;i++) {
-		rs_disable_rx_interrupts(port); 
-		rs_disable_tx_interrupts(port); 
+	for (i=0; i < MPC5xxx_PSC_NPORTS; i++) {
+		rs_disable_rx_interrupts(port);
+		rs_disable_tx_interrupts(port);
+		switch ((int) port->psc) {
+			case MPC5xxx_PSC1: { sprintf(name, "PSC1"); break; }
+			case MPC5xxx_PSC2: { sprintf(name, "PSC2"); break; }
+			case MPC5xxx_PSC3: { sprintf(name, "PSC3"); break; }
+			case MPC5xxx_PSC4: { sprintf(name, "PSC4"); break; }
+			case MPC5xxx_PSC5: { sprintf(name, "PSC5"); break; }
+			case MPC5xxx_PSC6: { sprintf(name, "PSC6"); break; }
+			default: { sprintf(name, "PSC?"); break; }
+		}
+
 		if (request_irq(port->irq, rs_interrupt,
 			SA_SHIRQ | SA_INTERRUPT, "serial", port)) {
-			printk(KERN_ERR
-				"rs: Cannot allocate irq for PSC%d.\n", i+1);
+			printk(KERN_ERR "rs: Cannot allocate irq for %s (ttyS%d).\n", name, i);
 			rc = 0;
 			continue;
 		}
 		rs_dprintk(MPC5xxx_PSC_DEBUG_INIT,
 				"requested irq for port[%d] = %08x\n",
 				i, (u32)port);
-		printk(KERN_INFO "ttyS%d on PSC%d\n", i, i+1);
+		printk(KERN_INFO "ttyS%d on %s\n", i, name);
 		port++;
 	}
 
@@ -940,25 +1030,27 @@
 	/*
 	 * Turn PSC interrupts off
 	 */
-	out_be16(&psc->mpc5xxx_psc_imr, 0);
+	psc->mpc5xxx_psc_imr = 0;
 
 	/*
 	 * Wait for the Tx register to become empty
 	 */
 	i = BUSY_WAIT;
-	while (!(in_be16(&psc->mpc5xxx_psc_status) & MPC5xxx_PSC_SR_TXEMP) &&
-			i--)
+	while (!(psc->mpc5xxx_psc_status & MPC5xxx_PSC_SR_TXEMP) && i--) {
 		udelay(1);
-	out_8(&psc->mpc5xxx_psc_buffer_8, c);
+	}
+
+	psc->mpc5xxx_psc_buffer_8 = c;
+
 	i = BUSY_WAIT;
-	while (!(in_be16(&psc->mpc5xxx_psc_status) & MPC5xxx_PSC_SR_TXEMP) &&
-			i--)
+	while (!(psc->mpc5xxx_psc_status & MPC5xxx_PSC_SR_TXEMP) && i--) {
 		udelay(1);
+	}
 
 	/*
 	 * Turn PSC interrupts back on
 	 */
-	out_be16(&psc->mpc5xxx_psc_imr, port->imr);
+	psc->mpc5xxx_psc_imr = port->imr;
 }
 
 static void serial_console_write(struct console *co, const char *s,
@@ -1050,17 +1142,14 @@
 		break;
 	}
 
-	out_8(&psc->command, MPC5xxx_PSC_RST_TX
-			| MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE);
-	out_8(&psc->command, MPC5xxx_PSC_RST_RX);
-
-	out_be32(&psc->sicr, 0x0);
-	out_be16(&psc->mpc5xxx_psc_clock_select, 0xdd00);
-	out_be16(&psc->tfalarm, 0xf8);
-
-	out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1
-			| MPC5xxx_PSC_RX_ENABLE
-			| MPC5xxx_PSC_TX_ENABLE);
+	psc->command = MPC5xxx_PSC_RST_TX | MPC5xxx_PSC_RX_DISABLE | MPC5xxx_PSC_TX_ENABLE;
+	psc->command = MPC5xxx_PSC_RST_RX;
+
+	psc->sicr = 0x0;
+	psc->mpc5xxx_psc_clock_select = 0xdd00;
+	psc->tfalarm = 0xf8;
+
+	psc->command = MPC5xxx_PSC_SEL_MODE_REG_1 | MPC5xxx_PSC_RX_ENABLE | MPC5xxx_PSC_TX_ENABLE;
 
 #ifdef CONFIG_UBOOT
 	divisor = ((bd->bi_ipbfreq / (baud * 16)) + 1) >> 1;	/* round up */
@@ -1071,11 +1160,11 @@
 	mode1 = bits | parity | MPC5xxx_PSC_MODE_ERR;
 	mode2 = MPC5xxx_PSC_MODE_ONE_STOP;
 
-	out_8(&psc->ctur, divisor>>8);
-	out_8(&psc->ctlr, divisor);
-	out_8(&psc->command, MPC5xxx_PSC_SEL_MODE_REG_1);
-	out_8(&psc->mode, mode1);
-	out_8(&psc->mode, mode2);
+	psc->ctur = divisor >> 8;
+	psc->ctlr = divisor;
+	psc->command = MPC5xxx_PSC_SEL_MODE_REG_1;
+	psc->mode = mode1;
+	psc->mode = mode2;
 
 	return 0;
 }
@@ -1095,3 +1184,51 @@
 }
 
 #endif
+
+static int sio_read_info(char *buf, char **start, off_t offset, int count, int  *eof, void *data)
+{
+	struct rs_port *port;
+	struct mpc5xxx_psc *psc;
+	u16 nStat;
+	int len = 0;
+
+	port = (struct rs_port *) data;
+	psc = port->psc;
+	nStat = psc->mpc5xxx_psc_status;
+
+	switch ((int) psc) {
+		case MPC5xxx_PSC1: { len += sprintf(buf+len, "PSC1: "); break; }
+		case MPC5xxx_PSC2: { len += sprintf(buf+len, "PSC2: "); break; }
+		case MPC5xxx_PSC3: { len += sprintf(buf+len, "PSC3: "); break; }
+		case MPC5xxx_PSC4: { len += sprintf(buf+len, "PSC4: "); break; }
+		case MPC5xxx_PSC5: { len += sprintf(buf+len, "PSC5: "); break; }
+		case MPC5xxx_PSC6: { len += sprintf(buf+len, "PSC6: "); break; }
+		default: { len += sprintf(buf+len, "PSC?: "); break; }
+	}
+	len += sprintf(buf+len, "Baudrate=%d, ", port->baud);
+	len += sprintf(buf+len, "Flags=0x%04x, ", port->cflag);
+	len += sprintf(buf+len, "Status=0x%04x ", nStat);
+	len += sprintf(buf+len, "Irq=%d, ", port->irq);
+	len += sprintf(buf+len, "Base=0x%08x\n      ", port->psc);
+	len += sprintf(buf+len, "RB:%d, ",(nStat & MPC5xxx_PSC_SR_RB) ? 1 : 0);
+	len += sprintf(buf+len, "FE:%d, ",(nStat & MPC5xxx_PSC_SR_FE) ? 1 : 0);
+	len += sprintf(buf+len, "PE:%d, ",(nStat & MPC5xxx_PSC_SR_PE) ? 1 : 0);
+	len += sprintf(buf+len, "OR:%d, ",(nStat & MPC5xxx_PSC_SR_OE) ? 1 : 0);
+	len += sprintf(buf+len, "TxEMP:%d, ",(nStat & MPC5xxx_PSC_SR_TXEMP) ? 1 : 0);
+	len += sprintf(buf+len, "TxRDY:%d, ",(nStat & MPC5xxx_PSC_SR_TXRDY) ? 1 : 0);
+	len += sprintf(buf+len, "RXFULL:%d, ",(nStat & MPC5xxx_PSC_SR_RXFULL) ? 1 : 0);
+	len += sprintf(buf+len, "RxRDY:%d, ",(nStat & MPC5xxx_PSC_SR_RXRDY) ? 1 : 0);
+	len += sprintf(buf+len, "CDE:%d\n",(nStat & MPC5xxx_PSC_SR_CDE) ? 1 : 0);
+
+	if (len <= offset + count)
+		*eof = 1;
+	*start = buf + offset;
+	len -= offset;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+

^ permalink raw reply

* [PATCH] powerpc: Add platform support for MPC834x USB controllers
From: Kumar Gala @ 2006-02-02 18:31 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Setup the platform devices needed by the Freescale EHCI USB
host controllers based on a flat device tree

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

---
commit 7ddda6a6630d95f800fbf848b00bd1d685c9bba4
tree 1d20b1c54ce3f28c1c103560bad4abf31ccdc00f
parent 9a8e139654ff5807b5b8fc3f73e9d118f22a3947
author Kumar Gala <galak@kernel.crashing.org> Thu, 02 Feb 2006 12:37:33 -0600
committer Kumar Gala <galak@kernel.crashing.org> Thu, 02 Feb 2006 12:37:33 -0600

 arch/powerpc/sysdev/fsl_soc.c |  140 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 140 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index e0887d5..ceb5846 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -351,3 +351,143 @@ nodev:
 
 arch_initcall(mpc83xx_wdt_init);
 #endif
+
+static enum fsl_usb2_phy_modes determine_usb_phy(char * phy_type)
+{
+	if (!phy_type)
+		return FSL_USB2_PHY_NONE;
+	if (!strcasecmp(phy_type, "ulpi"))
+		return FSL_USB2_PHY_ULPI;
+	if (!strcasecmp(phy_type, "utmi"))
+		return FSL_USB2_PHY_UTMI;
+	if (!strcasecmp(phy_type, "utmi_wide"))
+		return FSL_USB2_PHY_UTMI_WIDE;
+	if (!strcasecmp(phy_type, "serial"))
+		return FSL_USB2_PHY_SERIAL;
+
+	return FSL_USB2_PHY_NONE;
+}
+
+static int __init fsl_usb_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *usb_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL;
+	     i++) {
+		struct resource r[2];
+		struct fsl_usb2_platform_data usb_data;
+		unsigned char *prop = NULL;
+
+		memset(&r, 0, sizeof(r));
+		memset(&usb_data, 0, sizeof(usb_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+
+		r[1].start = np->intrs[0].line;
+		r[1].end = np->intrs[0].line;
+		r[1].flags = IORESOURCE_IRQ;
+
+		usb_dev =
+		    platform_device_register_simple("fsl-usb2-mph", i, r, 2);
+		if (IS_ERR(usb_dev)) {
+			ret = PTR_ERR(usb_dev);
+			goto err;
+		}
+
+		usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
+		usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
+
+		usb_data.operating_mode = FSL_USB2_MPH_HOST;
+
+		prop = get_property(np, "port0", NULL);
+		if (prop)
+			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
+
+		prop = get_property(np, "port1", NULL);
+		if (prop)
+			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
+
+		prop = get_property(np, "phy_type", NULL);
+		usb_data.phy_mode = determine_usb_phy(prop);
+
+		ret =
+		    platform_device_add_data(usb_dev, &usb_data,
+					     sizeof(struct
+						    fsl_usb2_platform_data));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(usb_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fsl_usb_of_init);
+
+static int __init fsl_usb_dr_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *usb_dev;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL;
+	     i++) {
+		struct resource r[2];
+		struct fsl_usb2_platform_data usb_data;
+		unsigned char *prop = NULL;
+
+		memset(&r, 0, sizeof(r));
+		memset(&usb_data, 0, sizeof(usb_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+
+		r[1].start = np->intrs[0].line;
+		r[1].end = np->intrs[0].line;
+		r[1].flags = IORESOURCE_IRQ;
+
+		usb_dev =
+		    platform_device_register_simple("fsl-usb2-dr", i, r, 2);
+		if (IS_ERR(usb_dev)) {
+			ret = PTR_ERR(usb_dev);
+			goto err;
+		}
+
+		usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
+		usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
+
+		usb_data.operating_mode = FSL_USB2_DR_HOST;
+
+		prop = get_property(np, "phy_type", NULL);
+		usb_data.phy_mode = determine_usb_phy(prop);
+
+		ret =
+		    platform_device_add_data(usb_dev, &usb_data,
+					     sizeof(struct
+						    fsl_usb2_platform_data));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(usb_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fsl_usb_dr_of_init);

^ permalink raw reply related

* [PATCH] Add fec support for mpc52xx
From: John Rigby @ 2006-02-02 18:21 UTC (permalink / raw)
  To: Sylvain Munaut, linuxppc-release, linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 73 bytes --]

Adds fec support, requires bestcom patch.  Applies to Sylvains git tree.

[-- Attachment #2: 0002-Add-fec-support-for-mpc52xx.txt --]
[-- Type: text/x-csrc, Size: 60840 bytes --]

Subject: [PATCH] Add fec support for mpc52xx

Signed-off-by: John Rigby <jrigby@freescale.com>

---

 drivers/net/Kconfig              |    2 
 drivers/net/Makefile             |    1 
 drivers/net/fec_mpc52xx/Kconfig  |   27 +
 drivers/net/fec_mpc52xx/Makefile |   12 
 drivers/net/fec_mpc52xx/fec.c    | 1556 ++++++++++++++++++++++++++++++++++++++
 drivers/net/fec_mpc52xx/fec.h    |  402 ++++++++++
 include/asm-ppc/mpc52xx.h        |    3 
 7 files changed, 2003 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fec_mpc52xx/Kconfig
 create mode 100644 drivers/net/fec_mpc52xx/Makefile
 create mode 100644 drivers/net/fec_mpc52xx/fec.c
 create mode 100644 drivers/net/fec_mpc52xx/fec.h

3b40e9de53a92ad8aa8e31ccb1378e9ade350c4e
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 626508a..763ffcf 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -920,6 +920,8 @@ config NI65
 
 source "drivers/net/tulip/Kconfig"
 
+source "drivers/net/fec_mpc52xx/Kconfig"
+
 config AT1700
 	tristate "AT1700/1720 support (EXPERIMENTAL)"
 	depends on NET_ETHERNET && (ISA || MCA_LEGACY) && EXPERIMENTAL
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 00e72b1..e18287e 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_SHAPER) += shaper.o
 obj-$(CONFIG_HP100) += hp100.o
 obj-$(CONFIG_SMC9194) += smc9194.o
 obj-$(CONFIG_FEC) += fec.o
+obj-$(CONFIG_PPC_5xxx_FEC) += fec_mpc52xx/
 obj-$(CONFIG_68360_ENET) += 68360enet.o
 obj-$(CONFIG_ARM_ETHERH) += 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
diff --git a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig
new file mode 100644
index 0000000..f72dfe0
--- /dev/null
+++ b/drivers/net/fec_mpc52xx/Kconfig
@@ -0,0 +1,27 @@
+#
+# MPC52xx Communication options
+#
+
+#menu "MPC5xxx I/O Options"
+#	depends on PPC_MPC52xx
+
+config PPC_5xxx_FEC
+	bool "FEC Ethernet on MPC52xx"
+	depends on NET_ETHERNET
+	default n
+	help
+	  Enable Ethernet support via the fast ethernet controller.
+
+config FEC_USE_MDIO
+	bool "Use MDIO for PHY configuration"
+	depends on PPC_5xxx_FEC
+
+config FEC_GENERIC_PHY
+	bool "Generic PHY support"
+	depends on FEC_USE_MDIO
+
+config FEC_LXT971
+	bool "Support LXT971 PHY"
+	depends on FEC_USE_MDIO
+	
+#endmenu
diff --git a/drivers/net/fec_mpc52xx/Makefile b/drivers/net/fec_mpc52xx/Makefile
new file mode 100644
index 0000000..5e85101
--- /dev/null
+++ b/drivers/net/fec_mpc52xx/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux MPC5xxx ppc-specific BestComm
+# peripheral controller
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+
+EXTRA_CFLAGS += -I$(TOPDIR)/arch/ppc/syslib/bestcomm/include \
+	        -I$(TOPDIR)/arch/ppc/syslib/bestcomm/capi \
+	        -I$(TOPDIR)/arch/ppc/syslib/bestcomm/capi/task_api \
+	        -I$(TOPDIR)/arch/ppc/syslib/bestcomm/code_dma/image_rtos1
+
+obj-$(CONFIG_PPC_5xxx_FEC)	+= fec.o
diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
new file mode 100644
index 0000000..0bb3e8f
--- /dev/null
+++ b/drivers/net/fec_mpc52xx/fec.c
@@ -0,0 +1,1556 @@
+/*
+ * arch/ppc/5xxx_io/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ * Support for MPC5100 FEC has been removed, contact the author if you need it
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ * 2.6 port by Bernhard Kuhn <bkuhn@metrowerks.com>
+ *
+ * 2003 (c) MontaVista, Software, Inc.  This file is licensed under the terms
+ * of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#define CONFIG_UBOOT
+
+static const char *version = "fec.c v0.2\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <asm/delay.h>
+#include "fec.h"
+#ifdef CONFIG_UBOOT
+#include <asm/ppcboot.h>
+#endif
+
+#ifdef CONFIG_NET_FASTROUTE
+#error "Fast Routing on MPC5200 ethernet not supported"
+#endif
+
+static struct net_device *mpc52xx_fec_dev;
+static irqreturn_t mpc52xx_fec_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t mpc52xx_fec_receive_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t mpc52xx_fec_transmit_interrupt(int, void *, struct pt_regs *);
+static struct net_device_stats *mpc52xx_fec_get_stats(struct net_device *);
+static void mpc52xx_fec_set_multicast_list(struct net_device *dev);
+static void mpc52xx_fec_reinit(struct net_device* dev);
+static int mpc52xx_fec_setup(struct net_device *dev, int reinit);
+static int mpc52xx_fec_cleanup(struct net_device *dev, int reinit);
+
+#ifdef CONFIG_FEC_USE_MDIO
+static void mpc52xx_fec_mii(struct net_device *dev);
+static int mpc52xx_fec_ioctl(struct net_device *, struct ifreq *rq, int cmd);
+static int mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr);
+#ifdef CONFIG_FEC_USE_MDIO_NOT_YET
+static void mpc52xx_mdio_callback(uint regval, struct net_device *dev, uint data);
+static int mpc52xx_mdio_read(struct net_device *dev, int phy_id, int location);
+#endif
+
+/* MII processing.  We keep this as simple as possible.  Requests are
+ * placed on the list (if there is room).  When the request is finished
+ * by the MII, an optional function may be called.
+ */
+typedef struct mii_list {
+	uint    mii_regval;
+	void    (*mii_func)(uint val, struct net_device *dev, uint data);
+	struct  mii_list *mii_next;
+	uint    mii_data;
+} mii_list_t;
+
+#define		NMII	20
+mii_list_t      mii_cmds[NMII];
+mii_list_t      *mii_free;
+mii_list_t      *mii_head;
+mii_list_t      *mii_tail;
+
+typedef struct mdio_read_data {
+	u16 regval;
+	struct task_struct *sleeping_task;
+} mdio_read_data_t;
+
+static int mii_queue(struct net_device *dev, int request,
+		void (*func)(uint, struct net_device *, uint), uint data);
+
+/* Make MII read/write commands for the FEC.
+ * */
+#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
+#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | \
+							(VAL & 0xffff))
+#define mk_mii_end	0
+
+/* Register definitions for the PHY.
+*/
+
+#define MII_REG_CR	 0	/* Control Register */
+#define MII_REG_SR	 1	/* Status Register */
+#define MII_REG_PHYIR1	 2	/* PHY Identification Register 1 */
+#define MII_REG_PHYIR2	 3	/* PHY Identification Register 2 */
+#define MII_REG_ANAR	 4	/* A-N Advertisement Register */
+#define MII_REG_ANLPAR	 5	/* A-N Link Partner Ability Register */
+#define MII_REG_ANER	 6	/* A-N Expansion Register */
+#define MII_REG_ANNPTR	 7	/* A-N Next Page Transmit Register */
+#define MII_REG_ANLPRNPR 8	/* A-N Link Partner Received Next Page Reg. */
+
+/* values for phy_status */
+
+#define PHY_CONF_ANE	0x0001	/* 1 auto-negotiation enabled */
+#define PHY_CONF_LOOP	0x0002	/* 1 loopback mode enabled */
+#define PHY_CONF_SPMASK	0x00f0	/* mask for speed */
+#define PHY_CONF_10HDX	0x0010	/* 10 Mbit half duplex supported */
+#define PHY_CONF_10FDX	0x0020	/* 10 Mbit full duplex supported */
+#define PHY_CONF_100HDX	0x0040	/* 100 Mbit half duplex supported */
+#define PHY_CONF_100FDX	0x0080	/* 100 Mbit full duplex supported */
+
+#define PHY_STAT_LINK	0x0100	/* 1 up - 0 down */
+#define PHY_STAT_FAULT	0x0200	/* 1 remote fault */
+#define PHY_STAT_ANC	0x0400	/* 1 auto-negotiation complete	*/
+#define PHY_STAT_SPMASK	0xf000	/* mask for speed */
+#define PHY_STAT_10HDX	0x1000	/* 10 Mbit half duplex selected	*/
+#define PHY_STAT_10FDX	0x2000	/* 10 Mbit full duplex selected	*/
+#define PHY_STAT_100HDX	0x4000	/* 100 Mbit half duplex selected */
+#define PHY_STAT_100FDX	0x8000	/* 100 Mbit full duplex selected */
+
+#endif	/* CONFIG_FEC_USE_MDIO */
+
+u8 mpc52xx_fec_mac_addr[6];
+u8 null_mac[6];
+
+static void mpc52xx_fec_tx_timeout(struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+
+	priv->stats.tx_errors++;
+
+	if (!priv->tx_full)
+		netif_wake_queue(dev);
+}
+
+static void
+mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	out_be32(&fec->paddr1, (mac[0]<<24) | (mac[1]<<16)
+			| (mac[2]<<8) | (mac[3]<<0));
+	out_be32(&fec->paddr2, (mac[4]<<24) | (mac[5]<<16) | 0x8808);
+}
+
+static int
+mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sock = (struct sockaddr *)addr;
+
+	mpc52xx_fec_set_paddr(dev, sock->sa_data);
+	return 0;
+}
+
+/* This function is called to start or restart the FEC during a link
+ * change.  This happens on fifo errors or when switching between half
+ * and full duplex.
+ */
+static void
+mpc52xx_fec_restart(struct net_device *dev, int duplex)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	u32 rcntrl;
+	u32 tcntrl;
+	int i;
+
+	out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & 0x700000);
+	out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & 0x700000);
+	out_be32(&fec->reset_cntrl, 0x1000000);
+
+	/* Whack a reset.  We should wait for this. */
+	out_be32(&fec->ecntrl, MPC52xx_FEC_ECNTRL_RESET);
+	for (i = 0; i < MPC52xx_FEC_RESET_DELAY; ++i) {
+		if ((in_be32(&fec->ecntrl) & MPC52xx_FEC_ECNTRL_RESET) == 0)
+			break;
+		udelay(1);
+	}
+	if (i == MPC52xx_FEC_RESET_DELAY)
+		printk ("FEC Reset timeout!\n");
+
+	/* Set station address. */
+	out_be32(&fec->paddr1, *(u32 *)&dev->dev_addr[0]);
+	out_be32(&fec->paddr2,
+		((*(u16 *)&dev->dev_addr[4]) << 16) | 0x8808);
+
+	mpc52xx_fec_set_multicast_list(dev);
+
+	rcntrl = MPC52xx_FEC_RECV_BUFFER_SIZE << 16;	/* max frame length */
+	rcntrl |= MPC52xx_FEC_RCNTRL_FCE;
+#ifdef	CONFIG_FEC_USE_MDIO
+	rcntrl |= MPC52xx_FEC_RCNTRL_MII_MODE;
+#endif
+	if (duplex)
+		tcntrl = MPC52xx_FEC_TCNTRL_FDEN;		/* FD enable */
+	else {
+		rcntrl |= MPC52xx_FEC_RCNTRL_DRT;
+		tcntrl = 0;
+	}
+	out_be32(&fec->r_cntrl, rcntrl);
+	out_be32(&fec->x_cntrl, tcntrl);
+
+#ifdef CONFIG_FEC_USE_MDIO
+	/* Set MII speed. */
+	out_be32(&fec->mii_speed, priv->phy_speed);
+#endif
+
+	priv->full_duplex = duplex;
+
+	/* Clear any outstanding interrupt. */
+	out_be32(&fec->ievent, 0xffffffff);	/* clear intr events */
+
+	/* Enable interrupts we wish to service.
+	*/
+#ifdef CONFIG_FEC_USE_MDIO
+	out_be32(&fec->imask, 0xf0fe0000);	/* enable all intr but tfint */
+#else
+	out_be32(&fec->imask, 0xf07e0000);	/* enable all intr but tfint */
+#endif
+
+	/* And last, enable the transmit and receive processing.
+	*/
+	out_be32(&fec->ecntrl, MPC52xx_FEC_ECNTRL_ETHER_EN);
+	out_be32(&fec->r_des_active, 0x01000000);
+
+	/* The tx ring is no longer full. */
+	if (priv->tx_full)
+	{
+		priv->tx_full = 0;
+		netif_wake_queue(dev);
+	}
+}
+
+#ifdef	CONFIG_FEC_USE_MDIO
+static void
+mpc52xx_fec_mii(struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	mii_list_t	*mip;
+	uint		mii_reg;
+
+	mii_reg = in_be32(&fec->mii_data);
+
+	if ((mip = mii_head) == NULL) {
+		printk("MII and no head!\n");
+		return;
+	}
+
+	if (mip->mii_func != NULL)
+		(*(mip->mii_func))(mii_reg, dev, mip->mii_data);
+
+	mii_head = mip->mii_next;
+	mip->mii_next = mii_free;
+	mii_free = mip;
+
+	if ((mip = mii_head) != NULL)
+		out_be32(&fec->mii_data, mip->mii_regval);
+}
+
+static int
+mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *, uint), uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	unsigned long	flags;
+	mii_list_t	*mip;
+	int		retval;
+
+	/* Add PHY address to register command.
+	*/
+	regval |= priv->phy_addr << 23;
+
+	retval = 0;
+
+	save_flags(flags);
+	cli();
+
+	if ((mip = mii_free) != NULL) {
+		mii_free = mip->mii_next;
+		mip->mii_regval = regval;
+		mip->mii_func = func;
+		mip->mii_next = NULL;
+		mip->mii_data = data;
+		if (mii_head) {
+			mii_tail->mii_next = mip;
+			mii_tail = mip;
+		} else {
+			mii_head = mii_tail = mip;
+			out_be32(&fec->mii_data, regval);
+		}
+	} else
+		retval = 1;
+
+	restore_flags(flags);
+
+	return retval;
+}
+
+static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
+{
+	int k;
+
+	if (!c)
+		return;
+
+	for (k = 0; (c+k)->mii_data != mk_mii_end; k++)
+		mii_queue(dev, (c+k)->mii_data, (c+k)->funct, 0);
+}
+
+static void mii_parse_sr(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
+
+	if (mii_reg & 0x0004)
+		s |= PHY_STAT_LINK;
+	if (mii_reg & 0x0010)
+		s |= PHY_STAT_FAULT;
+	if (mii_reg & 0x0020)
+		s |= PHY_STAT_ANC;
+
+	priv->phy_status = s;
+}
+
+static void mii_parse_cr(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);
+
+	if (mii_reg & 0x1000)
+		s |= PHY_CONF_ANE;
+	if (mii_reg & 0x4000)
+		s |= PHY_CONF_LOOP;
+
+	priv->phy_status = s;
+}
+
+static void mii_parse_anar(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_CONF_SPMASK);
+
+	if (mii_reg & 0x0020)
+		s |= PHY_CONF_10HDX;
+	if (mii_reg & 0x0040)
+		s |= PHY_CONF_10FDX;
+	if (mii_reg & 0x0080)
+		s |= PHY_CONF_100HDX;
+	if (mii_reg & 0x0100)
+		s |= PHY_CONF_100FDX;
+
+	priv->phy_status = s;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Generic PHY support.  Should work for all PHYs, but does not support link
+ * change interrupts.
+ */
+#ifdef CONFIG_FEC_GENERIC_PHY
+
+static phy_info_t phy_info_generic = {
+	0x00000000, /* 0-->match any PHY */
+	"GENERIC",
+
+	(const phy_cmd_t []) {  /* config */
+		/* advertise only half-duplex capabilities */
+		{ mk_mii_write(MII_ADVERTISE, MII_ADVERTISE_HALF),
+			mii_parse_anar },
+
+		/* enable auto-negotiation */
+		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE), mii_parse_cr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* startup */
+		/* restart auto-negotiation */
+		{ mk_mii_write(MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)),
+			NULL },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) { /* ack_int */
+		/* We don't actually use the ack_int table with a generic
+		 * PHY, but putting a reference to mii_parse_sr here keeps
+		 * us from getting a compiler warning about unused static
+		 * functions in the case where we only compile in generic
+		 * PHY support.
+		 */
+		{ mk_mii_read(MII_BMSR), mii_parse_sr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {  /* shutdown */
+		{ mk_mii_end, }
+	},
+};
+#endif	/* CONFIG_FEC_GENERIC_PHY */
+
+/* ------------------------------------------------------------------------- */
+/* The Level one LXT971 is used on some of my custom boards		     */
+
+#ifdef CONFIG_FEC_LXT971
+
+/* register definitions for the 971 */
+
+#define MII_LXT971_PCR	16	/* Port Control Register	*/
+#define MII_LXT971_SR2	17	/* Status Register 2		*/
+#define MII_LXT971_IER	18	/* Interrupt Enable Register	*/
+#define MII_LXT971_ISR	19	/* Interrupt Status Register	*/
+#define MII_LXT971_LCR	20	/* LED Control Register		*/
+#define MII_LXT971_TCR	30	/* Transmit Control Register	*/
+
+static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	s &= ~(PHY_STAT_SPMASK);
+
+	if (mii_reg & 0x4000) {
+		if (mii_reg & 0x0200)
+			s |= PHY_STAT_100FDX;
+		else
+			s |= PHY_STAT_100HDX;
+	}
+	else {
+		if (mii_reg & 0x0200)
+			s |= PHY_STAT_10FDX;
+		else
+			s |= PHY_STAT_10HDX;
+	}
+	if (mii_reg & 0x0008)
+		s |= PHY_STAT_FAULT;
+
+	priv->full_duplex = ((mii_reg & 0x0200) != 0);
+
+	priv->phy_status = s;
+}
+
+static phy_info_t phy_info_lxt971 = {
+	0x0001378e,
+	"LXT971",
+
+	(const phy_cmd_t []) {	/* config */
+#ifdef MPC5100_FIX10HDX
+		{ mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10 Mbps, HD */
+#else
+/*		{ mk_mii_write(MII_REG_ANAR, 0x0A1), NULL }, *//*  10/100, HD */
+		{ mk_mii_write(MII_REG_ANAR, 0x01E1), NULL }, /* 10/100, FD */
+#endif
+		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
+		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {	/* startup - enable interrupts */
+		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
+		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+
+		/* Somehow does the 971 tell me that the link is down
+		 * the first read after power-up.
+		 * read here to get a valid value in ack_int */
+
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) { /* ack_int */
+		/* find out the current status */
+
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
+		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
+
+		/* we only need to read ISR to acknowledge */
+
+		{ mk_mii_read(MII_LXT971_ISR), NULL },
+		{ mk_mii_end, }
+	},
+	(const phy_cmd_t []) {	/* shutdown - disable interrupts */
+		{ mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
+		{ mk_mii_end, }
+	},
+};
+
+#endif /* CONFIG_FEC_LXT971 */
+
+static phy_info_t *phy_info[] = {
+
+#ifdef CONFIG_FEC_LXT971
+	&phy_info_lxt971,
+#endif /* CONFIG_FEC_LXT971 */
+
+#ifdef CONFIG_FEC_GENERIC_PHY
+	/* Generic PHY support.  This must be the last PHY in the table.
+	 * It will be used to support any PHY that doesn't match a previous
+	 * entry in the table.
+	 */
+	&phy_info_generic,
+#endif /* CONFIG_FEC_GENERIC_PHY */
+
+	NULL
+};
+
+static void mii_display_config(struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	uint s = priv->phy_status;
+
+	printk("%s: config: auto-negotiation ", dev->name);
+
+	if (s & PHY_CONF_ANE)
+		printk("on");
+	else
+		printk("off");
+
+	if (s & PHY_CONF_100FDX)
+		printk(", 100FDX");
+	if (s & PHY_CONF_100HDX)
+		printk(", 100HDX");
+	if (s & PHY_CONF_10FDX)
+		printk(", 10FDX");
+	if (s & PHY_CONF_10HDX)
+		printk(", 10HDX");
+	if (!(s & PHY_CONF_SPMASK))
+		printk(", No speed/duplex selected?");
+
+	if (s & PHY_CONF_LOOP)
+		printk(", loopback enabled");
+
+	printk(".\n");
+
+	priv->sequence_done = 1;
+}
+
+static void mii_queue_config(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+
+	priv->phy_task.func = (void *)mii_display_config;
+	priv->phy_task.data = dev;
+	schedule_work(&priv->phy_task);
+}
+
+
+phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config },
+			       { mk_mii_end, } };
+
+
+/* Read remainder of PHY ID.
+*/
+static void
+mii_discover_phy3(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	int	i;
+
+	priv->phy_id |= (mii_reg & 0xffff);
+
+	for (i = 0; phy_info[i]; i++) {
+		if (phy_info[i]->id == (priv->phy_id >> 4) || !phy_info[i]->id)
+			break;
+		if (phy_info[i]->id == 0)	/* check generic entry */
+			break;
+	}
+
+	if (!phy_info[i])
+		panic("%s: PHY id 0x%08x is not supported!\n",
+			dev->name, priv->phy_id);
+
+	priv->phy = phy_info[i];
+	priv->phy_id_done = 1;
+
+	printk("%s: Phy @ 0x%x, type %s (0x%08x)\n",
+		dev->name, priv->phy_addr, priv->phy->name, priv->phy_id);
+}
+
+/* Scan all of the MII PHY addresses looking for someone to respond
+ * with a valid ID.  This usually happens quickly.
+ */
+static void
+mii_discover_phy(uint mii_reg, struct net_device *dev, uint data)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	uint	phytype;
+
+	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
+		/* Got first part of ID, now get remainder.
+		*/
+		priv->phy_id = phytype << 16;
+		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3, 0);
+	} else {
+		priv->phy_addr++;
+		if (priv->phy_addr < 32)
+			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
+							mii_discover_phy, 0);
+		else
+			printk("fec: No PHY device found.\n");
+	}
+}
+#endif	/* CONFIG_FEC_USE_MDIO */
+
+
+#define RFIFO_DATA	0xf0003184
+#define TFIFO_DATA	0xf00031a4
+
+/*
+ * Initialize FEC receive task.
+ * Returns task number of FEC receive task.
+ * Returns -1 on failure
+ */
+int
+mpc52xx_fec_rx_task_setup(int num_bufs, int maxbufsize)
+{
+	static TaskSetupParamSet_t params;
+	int tasknum;
+
+	params.NumBD = num_bufs;
+	params.Size.MaxBuf = maxbufsize;
+	params.StartAddrSrc = RFIFO_DATA;
+	params.IncrSrc = 0;
+	params.SzSrc = 4;
+	params.IncrDst = 4;
+	params.SzDst = 4;
+
+	tasknum = TaskSetup(TASK_FEC_RX, &params);
+
+	/* clear pending interrupt bits */
+	TaskIntClear(tasknum);
+
+	return tasknum;
+}
+
+/*
+ * Initialize FEC transmit task.
+ * Returns task number of FEC transmit task.
+ * Returns -1 on failure
+ */
+int
+mpc52xx_fec_tx_task_setup(int num_bufs)
+{
+	static TaskSetupParamSet_t params;
+	int tasknum;
+
+	params.NumBD = num_bufs;
+	params.IncrSrc = 4;
+	params.SzSrc = 4;
+	params.StartAddrDst = TFIFO_DATA;
+	params.IncrDst = 0;
+	params.SzDst = 4;
+
+	tasknum = TaskSetup(TASK_FEC_TX, &params);
+
+	/* clear pending interrupt bits */
+	TaskIntClear(tasknum);
+
+	return tasknum;
+}
+
+
+static volatile int tx_fifo_cnt, tx_fifo_ipos, tx_fifo_opos;
+static struct sk_buff *tx_fifo_skb[MPC52xx_FEC_TBD_NUM];
+
+static volatile int rx_fifo_cnt, rx_fifo_ipos, rx_fifo_opos;
+static struct sk_buff *rx_fifo_skb[MPC52xx_FEC_RBD_NUM];
+
+static int
+mpc52xx_fec_setup(struct net_device *dev, int reinit)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct sk_buff *skb;
+	int i;
+	struct mpc52xx_rbuf *rbuf;
+	struct mpc52xx_fec *fec = priv->fec;
+#if 0
+	u32 u32_value;
+#endif
+	u16 u16_value;
+
+	mpc52xx_fec_set_paddr(dev, dev->dev_addr);
+
+	/*
+	 * Initialize receive queue
+	 */
+	priv->r_tasknum = mpc52xx_fec_rx_task_setup(MPC52xx_FEC_RBD_NUM,
+						    MPC52xx_FEC_RECV_BUFFER_SIZE);
+	TaskBDReset(priv->r_tasknum);
+	for(i=0;i<MPC52xx_FEC_RBD_NUM;i++) {
+	  skb = dev_alloc_skb(sizeof *rbuf);
+	  if (skb == 0)
+	    goto eagain;
+	  skb->dev = dev;
+	  rbuf = (struct mpc52xx_rbuf *)skb_put(skb, sizeof *rbuf);
+	  invalidate_dcache_range((u32)rbuf, (u32)rbuf + sizeof *rbuf);
+	  rx_fifo_skb[i]=skb;
+	  TaskBDAssign(priv->r_tasknum, (void*)virt_to_phys((void *)&rbuf->data),
+		       0, sizeof *rbuf, MPC52xx_FEC_RBD_INIT);
+	};
+	rx_fifo_cnt = rx_fifo_ipos = rx_fifo_opos = 0;
+#if 0
+	printk("fec_open:\n");
+	checkrxbd(dev);
+#endif
+
+	/*
+	 * Initialize transmit queue
+	 */
+	if(!reinit) {
+	  priv->t_tasknum = mpc52xx_fec_tx_task_setup(MPC52xx_FEC_TBD_NUM);
+	  TaskBDReset(priv->t_tasknum);
+	  for(i=0;i<MPC52xx_FEC_TBD_NUM;i++) tx_fifo_skb[i]=0;
+	  tx_fifo_cnt = tx_fifo_ipos = tx_fifo_opos = 0;
+
+#ifdef CONFIG_FEC_USE_MDIO
+	  if (reinit) {
+	    if (!priv->sequence_done) {
+	      if (!priv->phy) {
+		printk("mpc52xx_fec_open: PHY not configured\n");
+		return -ENODEV;		/* No PHY we understand */
+	      }
+	      
+	      mii_do_cmd(dev, priv->phy->config);
+	      mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
+	      while(!priv->sequence_done)
+		schedule();
+	      
+	      mii_do_cmd(dev, priv->phy->startup);
+	    }
+	  }
+#endif /* CONFIG_FEC_USE_MDIO */
+	  
+	  dev->irq = MPC52xx_FEC_IRQ;
+	  priv->r_irq = MPC52xx_SDMA_IRQ_BASE + priv->r_tasknum;
+	  priv->t_irq = MPC52xx_SDMA_IRQ_BASE + priv->t_tasknum;
+	  
+	  if (request_irq(dev->irq, &mpc52xx_fec_interrupt,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "eth_err", dev)) {
+	    panic("FEC interrupt allocation failed\n");
+	  }
+	  
+	  if (request_irq(priv->r_irq, &mpc52xx_fec_receive_interrupt,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "eth_recv", dev)) {
+	    panic("FEC receive task interrupt allocation failed\n");
+	  }
+	  
+	  if (request_irq(priv->t_irq, &mpc52xx_fec_transmit_interrupt,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "eth_xmit", dev)) {
+	    panic("FEC transmit task interrupt allocation failed\n");
+	  }
+	
+	};
+
+	out_be32(&fec->op_pause, 0x00010020);	/* change to 0xffff0020 ??? */
+	out_be32(&fec->rfifo_cntrl, 0x0f000000);
+	out_be32(&fec->rfifo_alarm, 0x0000030c);
+	out_be32(&fec->tfifo_cntrl, 0x0f000000);
+	out_be32(&fec->tfifo_alarm, 0x00000100);
+	out_be32(&fec->x_wmrk, 0x3);		/* xmit fifo watermark = 256 */
+	out_be32(&fec->xmit_fsm, 0x03000000);	/* enable crc generation */
+	out_be32(&fec->iaddr1, 0x00000000);	/* No individual filter */
+	out_be32(&fec->iaddr2, 0x00000000);	/* No individual filter */
+	
+#ifdef CONFIG_PPC_MPC52xx
+	/* Disable COMM Bus Prefetch */
+	u16_value = in_be16(&priv->sdma->PtdCntrl);
+	u16_value |= 1;
+	out_be16(&priv->sdma->PtdCntrl, u16_value);
+#endif
+
+	if(!reinit) {
+#if !defined(CONFIG_FEC_USE_MDIO)
+	  mpc52xx_fec_restart (dev, 0);	/* always use half duplex mode only */
+#else
+#ifdef CONFIG_UBOOT
+	  bd_t *bd = (bd_t *)&__res;
+#define MPC52xx_IPBFREQ bd->bi_ipbfreq
+#else
+#define MPC52xx_IPBFREQ CONFIG_PPC_52xx_IPBFREQ
+#endif
+	  for (i=0; i<NMII-1; i++)
+	    mii_cmds[i].mii_next = &mii_cmds[i+1];
+	  mii_free = mii_cmds;
+
+	  priv->phy_speed = (((MPC52xx_IPBFREQ >> 20) / 5) << 1);
+
+	  //mpc52xx_fec_restart (dev, 0);	/* half duplex, negotiate speed */
+	  mpc52xx_fec_restart (dev, 1);	/* full duplex, negotiate speed */
+	  
+	  /* Queue up command to detect the PHY and initialize the
+	   * remainder of the interface.
+	   */
+	  priv->phy_id_done = 0;
+	  priv->phy_addr = 0;
+	  mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
+	  
+	  priv->old_status = 0;
+
+#ifdef CONFIG_FEC_USE_MDIO
+	  if (reinit) {
+	    if (!priv->sequence_done) {
+	      if (!priv->phy) {
+		printk("mpc52xx_fec_open: PHY not configured\n");
+		return -ENODEV;		/* No PHY we understand */
+	      }
+	      
+	      mii_do_cmd(dev, priv->phy->config);
+	      mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
+	      while(!priv->sequence_done)
+		schedule();
+	      
+	      mii_do_cmd(dev, priv->phy->startup);
+	    }
+	  }
+#endif /* CONFIG_FEC_USE_MDIO */
+#endif
+	}
+	else {
+	  mpc52xx_fec_restart (dev, 0);
+	};
+
+	netif_start_queue(dev);
+
+	TaskStart(priv->r_tasknum, TASK_AUTOSTART_ENABLE,
+		  priv->r_tasknum, TASK_INTERRUPT_ENABLE);
+
+	if(reinit) {
+	  TaskStart(priv->t_tasknum, TASK_AUTOSTART_ENABLE,
+		    priv->t_tasknum, TASK_INTERRUPT_ENABLE);
+	};
+
+	return 0;
+
+eagain:
+	printk("mpc52xx_fec_open: failed\n");
+	for (i=0; i<MPC52xx_FEC_RBD_NUM; i++) {
+		skb = rx_fifo_skb[i];
+		if (skb == 0)
+			break;
+		dev_kfree_skb(skb);
+	}
+	TaskBDReset(priv->r_tasknum);
+
+	return -EAGAIN;
+}
+
+
+static int
+mpc52xx_fec_open(struct net_device *dev)
+{
+  int ret = mpc52xx_fec_setup(dev,0);
+  return ret;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+
+static int
+mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	int pad;
+	short length;
+	int bdi;
+
+	length = skb->len;
+#define MUST_ALIGN_TRANSMIT_DATA
+#ifdef	MUST_ALIGN_TRANSMIT_DATA
+	pad = (int)skb->data & 0x3;
+	if (pad) {
+		void *old_data = skb->data;
+		skb_push(skb, pad);
+		memcpy(skb->data, old_data, length);
+		skb_trim(skb, length);
+	}
+#endif
+	/* Zero out up to the minimum length ethernet packet size,
+	 * so we don't inadvertently expose sensitive data
+	 */ 
+	pad = ETH_ZLEN - skb->len;
+	if (pad > 0) {
+		skb = skb_pad(skb, pad);
+		if (skb == 0)
+			return 0;
+		length += pad;
+	}
+
+	flush_dcache_range((u32)skb->data, (u32)skb->data + length);
+
+	spin_lock_irq(&priv->lock);
+	bdi = TaskBDAssign(priv->t_tasknum,(void*)virt_to_phys((void *)skb->data),
+			   NULL,length,MPC52xx_FEC_TBD_INIT);
+
+	// sanity check: bdi must always equal tx_fifo_ipos
+	if(bdi!=tx_fifo_ipos) {
+	  printk("bdi!=tx_fifo_ipos: %i, %i\n",bdi,tx_fifo_ipos);
+	};
+
+	tx_fifo_skb[tx_fifo_ipos]=skb;
+	dev->trans_start = jiffies;
+        TaskStart(priv->t_tasknum, TASK_AUTOSTART_ENABLE,
+		  priv->t_tasknum, TASK_INTERRUPT_ENABLE);
+
+	tx_fifo_cnt++;
+	tx_fifo_ipos++;
+	if(tx_fifo_ipos==MPC52xx_FEC_TBD_NUM) tx_fifo_ipos=0;
+
+	if(tx_fifo_cnt==MPC52xx_FEC_TBD_NUM) {
+		priv->tx_full = 1;
+		netif_stop_queue(dev);
+		printk("fifo full\n");
+	};
+
+	spin_unlock_irq(&priv->lock);
+
+	return 0;
+}
+
+/* This handles SDMA transmit task interrupts
+ */
+static irqreturn_t 
+mpc52xx_fec_transmit_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = dev_id;
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	int bdi;
+
+	spin_lock(&priv->lock);
+
+	// Already ACK'ed in linux toplevel ISR 
+	// TaskIntClear(priv->t_tasknum);
+
+	while(tx_fifo_cnt) {
+	  if(TaskGetBD(priv->t_tasknum, tx_fifo_opos)->Status & MPC52xx_FEC_TBD_TFD)
+	    break;
+	  dev_kfree_skb_irq(tx_fifo_skb[tx_fifo_opos]);
+	  tx_fifo_skb[tx_fifo_opos]=0;
+	  bdi = TaskBDRelease(priv->t_tasknum);
+	  tx_fifo_cnt--;
+	  tx_fifo_opos++;
+	  if(tx_fifo_opos==MPC52xx_FEC_TBD_NUM) tx_fifo_opos=0;
+	  priv->tx_full = 0;
+
+	  // sanity check: bdi must always equal tx_fifo_opos
+	  if(bdi!=tx_fifo_opos) {
+	    printk("bdi!=tx_fifo_opos: %i, %i\n",bdi,tx_fifo_opos);
+	  };
+	};
+
+	if (netif_queue_stopped(dev) && !priv->tx_full)
+		netif_wake_queue(dev);
+
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t 
+mpc52xx_fec_receive_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = dev_id;
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct sk_buff *skb;
+	struct sk_buff *nskb;
+	struct mpc52xx_rbuf *rbuf;
+	struct mpc52xx_rbuf *nrbuf;
+	u32 status;
+	int length;
+
+	// Already ACK'ed in linux toplevel ISR 
+	// TaskIntClear(priv->r_tasknum);
+
+	for (;;) {
+		status = TaskGetBD(priv->r_tasknum,rx_fifo_opos)->Status;
+		if (!(status & MPC52xx_FEC_RBD_RFD))
+			break;
+		length = status & 0xffff;
+		skb = rx_fifo_skb[rx_fifo_opos];
+		rbuf = (struct mpc52xx_rbuf *)skb->data;
+
+		/* allocate replacement skb */
+		nskb = dev_alloc_skb(sizeof *nrbuf);
+		if (nskb == NULL) {
+			printk(KERN_NOTICE
+			"%s: Memory squeeze, dropping packet.\n",
+				dev->name);
+			priv->stats.rx_dropped++;
+			nrbuf = (struct mpc52xx_rbuf *)skb->data;
+		}
+		else {
+			nskb->dev = dev;
+			nrbuf = (struct mpc52xx_rbuf *)skb_put(nskb,
+					sizeof *nrbuf);
+
+			invalidate_dcache_range((u32)nrbuf,
+					(u32)nrbuf + sizeof *nrbuf);
+
+			skb_trim(skb, length);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			rx_fifo_skb[rx_fifo_opos] = nskb;
+
+		}
+
+		TaskBDRelease(priv->r_tasknum);
+		TaskBDAssign(priv->r_tasknum, (void*)virt_to_phys((void *)&nrbuf->data),
+			     0, sizeof *rbuf, MPC52xx_FEC_RBD_INIT);
+
+		rx_fifo_opos++;
+		if(rx_fifo_opos==MPC52xx_FEC_RBD_NUM) rx_fifo_opos=0;
+
+		if (!nskb)
+			break;
+
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static void mpc52xx_fec_reinit(struct net_device *dev)
+{
+  int retval;
+  printk("mpc52xx_fec_reinit\n");
+  mpc52xx_fec_cleanup(dev,1);
+  retval=mpc52xx_fec_setup(dev,1);
+  if(retval) panic("reinit failed\n");
+};
+
+
+#define LONG_REF(x) (*((volatile unsigned long*)x))
+#define SHORT_REF(x) (*((volatile unsigned short*)x))
+static void checkrxbd(struct net_device *dev) {
+  struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+#if 0
+  int stat[64];
+  int i;
+  for(i=0;i<64;i++) {
+    stat[i] = TaskGetBD(priv->r_tasknum,i)->Status;
+  };
+  for(i=0;i<64;i++) {
+    printk("status[%i]=0x%08x\n",i,stat[i]);
+  };
+#endif
+  printk("SDMA IRQ pending = 0x%08lx\n",LONG_REF(0xf0001214));
+  printk("SDMA IRQ mask    = 0x%08lx\n",LONG_REF(0xf0001218));
+  printk("SDMA Task CTRL0  = 0x%04x\n",SHORT_REF(0xf000121c));
+  printk("SDMA Task CTRL1  = 0x%04x\n",SHORT_REF(0xf000121e));
+  printk("SDMA Task CTRL2  = 0x%04x\n",SHORT_REF(0xf0001220));
+  printk("SDMA Task CTRL3  = 0x%04x\n",SHORT_REF(0xf0001222));
+  printk("SDMA Task CTRL4  = 0x%04x\n",SHORT_REF(0xf0001224));
+  printk("SDMA Task CTRL5  = 0x%04x\n",SHORT_REF(0xf0001226));
+  printk("SDMA Task CTRL6  = 0x%04x\n",SHORT_REF(0xf0001228));
+  printk("SDMA Task CTRL7  = 0x%04x\n",SHORT_REF(0xf000122a));
+  printk("SDMA Task CTRL8  = 0x%04x\n",SHORT_REF(0xf000122c));
+  printk("SDMA Task CTRL9  = 0x%04x\n",SHORT_REF(0xf000122e));
+  printk("SDMA Task CTRL10 = 0x%04x\n",SHORT_REF(0xf0001230));
+  printk("SDMA Task CTRL11 = 0x%04x\n",SHORT_REF(0xf0001232));
+  printk("SDMA Task CTRL12 = 0x%04x\n",SHORT_REF(0xf0001234));
+  printk("SDMA Task CTRL13 = 0x%04x\n",SHORT_REF(0xf0001236));
+  printk("SDMA Task CTRL14 = 0x%04x\n",SHORT_REF(0xf0001238));
+  printk("SDMA Task CTRL15 = 0x%04x\n",SHORT_REF(0xf000123a));
+  printk("r_tasknum=%i\n",priv->r_tasknum);
+  printk("t_tasknum=%i\n",priv->t_tasknum);
+};
+
+static irqreturn_t 
+mpc52xx_fec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	int ievent;
+
+	ievent = in_be32(&fec->ievent);
+	out_be32(&fec->ievent, ievent);		/* clear pending events */
+
+	if (ievent & (MPC52xx_FEC_IEVENT_RFIFO_ERROR |
+		      MPC52xx_FEC_IEVENT_XFIFO_ERROR)) {
+		if (ievent & MPC52xx_FEC_IEVENT_RFIFO_ERROR)
+			printk(KERN_WARNING "MPC52xx_FEC_IEVENT_RFIFO_ERROR\n");
+		if (ievent & MPC52xx_FEC_IEVENT_XFIFO_ERROR)
+			printk(KERN_WARNING "MPC52xx_FEC_IEVENT_XFIFO_ERROR\n");
+		printk("fec_irq:\n");
+		checkrxbd(dev);
+		mpc52xx_fec_reinit(dev);
+	}
+	else if (ievent & MPC52xx_FEC_IEVENT_MII) {
+#ifdef CONFIG_FEC_USE_MDIO
+		mpc52xx_fec_mii(dev);
+#else
+		printk("%s[%d] %s: unexpected MPC52xx_FEC_IEVENT_MII\n"
+			__FILE__, __LINE__, __FUNCTION__);
+#endif /* CONFIG_FEC_USE_MDIO */
+	}
+	else {
+	  printk("fec: ievent=0x%08x\n",ievent);
+	};
+	return IRQ_HANDLED;
+}
+
+static int
+mpc52xx_fec_cleanup(struct net_device *dev, int reinit)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	unsigned long timeout;
+	int i;
+
+	priv->open_time = 0;
+#ifdef CONFIG_FEC_USE_MDIO
+	priv->sequence_done = 0;
+#endif
+
+	netif_stop_queue(dev);
+
+	/* Wait for rx queue to drain */
+	if(!reinit) {
+	  timeout = jiffies + 2*HZ;
+	  while (tx_fifo_cnt && (jiffies < timeout)) {
+	    set_current_state(TASK_INTERRUPTIBLE);
+	    schedule_timeout(HZ/10);
+	  }
+	};
+
+	/* Disable FEC interrupts */
+	out_be32(&fec->imask, 0x0); 
+
+	/* Stop FEC */
+	out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~0x2);
+
+	/* Disable the rx and tx queues. */
+	TaskStop(priv->r_tasknum);
+	TaskStop(priv->t_tasknum);
+
+	/* Release irqs */
+	if(!reinit) {
+	  free_irq(dev->irq, dev);
+	  free_irq(priv->r_irq, dev);
+	  free_irq(priv->t_irq, dev);
+	};
+
+	/* Free rx Buffers */
+	if(!reinit) {
+	  for (i=0; i<MPC52xx_FEC_RBD_NUM; i++) {
+	    dev_kfree_skb(rx_fifo_skb[i]);
+	  };
+	}
+	else {
+	  for (i=0; i<MPC52xx_FEC_RBD_NUM; i++) {
+	    dev_kfree_skb_irq(rx_fifo_skb[i]);
+	  };
+	};
+	
+	mpc52xx_fec_get_stats(dev);
+
+	return 0;
+}
+
+static int
+mpc52xx_fec_close(struct net_device *dev)
+{
+  return mpc52xx_fec_cleanup(dev,0);
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *
+mpc52xx_fec_get_stats(struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+	stats->rx_packets = in_be32(&fec->rmon_r_packets);
+	stats->rx_errors = stats->rx_packets - in_be32(&fec->ieee_r_frame_ok);
+	stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+	stats->tx_packets = in_be32(&fec->rmon_t_packets);
+	stats->tx_errors = stats->tx_packets - (
+					in_be32(&fec->ieee_t_frame_ok) +
+					in_be32(&fec->rmon_t_col) +
+					in_be32(&fec->ieee_t_1col) +
+					in_be32(&fec->ieee_t_mcol) +
+					in_be32(&fec->ieee_t_def));
+	stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
+	stats->collisions = in_be32(&fec->rmon_t_col);
+
+	/* detailed rx_errors: */
+	stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
+			+ in_be32(&fec->rmon_r_oversize)
+			+ in_be32(&fec->rmon_r_frag)
+			+ in_be32(&fec->rmon_r_jab);
+	stats->rx_over_errors = in_be32(&fec->r_macerr);
+	stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
+	stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
+	stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
+	stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
+
+	/* detailed tx_errors: */
+	stats->tx_aborted_errors = 0;
+	stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
+	stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
+	stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
+	stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
+
+	return stats;
+}
+
+static void
+mpc52xx_fec_update_stat(struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	out_be32(&fec->mib_control, MPC52xx_FEC_MIB_DISABLE);
+	memset_io(&fec->rmon_t_drop, 0,
+			(u32)&fec->reserved10 - (u32)&fec->rmon_t_drop);
+	out_be32(&fec->mib_control, 0);
+	memset(stats, 0, sizeof *stats);
+	mpc52xx_fec_get_stats(dev);
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void
+mpc52xx_fec_set_multicast_list(struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = (struct mpc52xx_fec_priv *)dev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+	u32 u32_value;
+
+	if (dev->flags & IFF_PROMISC) {
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		u32_value = in_be32(&fec->r_cntrl);
+		u32_value |= MPC52xx_FEC_RCNTRL_PROM;
+		out_be32(&fec->r_cntrl, u32_value);
+	}
+	else if (dev->flags & IFF_ALLMULTI) {
+		u32_value = in_be32(&fec->r_cntrl);
+		u32_value &= ~MPC52xx_FEC_RCNTRL_PROM;
+		out_be32(&fec->r_cntrl, u32_value);
+		out_be32(&fec->gaddr1, 0xffffffff);
+		out_be32(&fec->gaddr2, 0xffffffff);
+	}
+	else {
+		u32 crc;
+		int i;
+		struct dev_mc_list *dmi;
+		u32 gaddr1 = 0x00000000;
+		u32 gaddr2 = 0x00000000;
+
+		dmi = dev->mc_list;
+		for (i=0; i<dev->mc_count; i++) {
+			crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
+			if (crc >= 32)
+				gaddr1 |= 1 << (crc-32);
+			else
+				gaddr2 |= 1 << crc;
+			dmi = dmi->next;
+		}
+		out_be32(&fec->gaddr1, gaddr1);
+		out_be32(&fec->gaddr2, gaddr2);
+	}
+}
+
+#ifdef CONFIG_FEC_USE_MDIO
+
+#ifdef CONFIG_FEC_USE_MDIO_NOT_YET
+static void mpc52xx_mdio_callback(uint regval, struct net_device *dev, uint data)
+{
+	mdio_read_data_t* mrd = (mdio_read_data_t *)data;
+	mrd->regval = 0xFFFF & regval;
+	wake_up_process(mrd->sleeping_task);
+}
+
+static int mpc52xx_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	uint retval;
+	mdio_read_data_t* mrd = (mdio_read_data_t *)kmalloc(sizeof(*mrd),
+			GFP_KERNEL);
+
+	mrd->sleeping_task = current;
+	set_current_state(TASK_INTERRUPTIBLE);
+	mii_queue(dev, mk_mii_read(location),
+		mpc52xx_mdio_callback, (unsigned int) mrd);
+	schedule();
+
+	retval = mrd->regval;
+
+	kfree(mrd);
+
+	return retval;
+}
+#endif
+
+void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	mii_queue(dev, mk_mii_write(location, value), NULL, 0);
+}
+#endif	/* CONFIG_FEC_USE_MDIO */
+
+static int
+mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+#ifdef CONFIG_FEC_USE_MDIO_NOT_YET_XXX
+	struct mpc52xx_fec_priv *private = (struct mpc52xx_fec_priv *)dev->priv;
+#endif
+	u32 ethcmd;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof ethcmd))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+		/* Get driver info */
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strncpy(info.driver, "gt64260",
+				sizeof info.driver - 1);
+			strncpy(info.version, version,
+				sizeof info.version - 1);
+			if (copy_to_user(useraddr, &info, sizeof info))
+				return -EFAULT;
+			return 0;
+		}
+		/* get settings */
+#ifdef CONFIG_FEC_USE_MDIO_NOT_YET_XXX
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+			spin_lock_irq(&private->lock);
+			mii_ethtool_gset(&private->mii_if, &ecmd);
+			spin_unlock_irq(&private->lock);
+			if (copy_to_user(useraddr, &ecmd, sizeof ecmd))
+				return -EFAULT;
+			return 0;
+		}
+		/* set settings */
+	case ETHTOOL_SSET:{
+			int r;
+			struct ethtool_cmd ecmd;
+			if (copy_from_user(&ecmd, useraddr, sizeof ecmd))
+				return -EFAULT;
+			spin_lock_irq(&private->lock);
+			r = mii_ethtool_sset(&private->mii_if, &ecmd);
+			spin_unlock_irq(&private->lock);
+			return r;
+		}
+		/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST:{
+			return mii_nway_restart(&private->mii_if);
+		}
+		/* get link status */
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
+			edata.data = mii_link_ok(&private->mii_if);
+			if (copy_to_user(useraddr, &edata, sizeof edata))
+				return -EFAULT;
+			return 0;
+		}
+#endif
+		/* get message-level */
+	case ETHTOOL_GMSGLVL:{
+			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+			edata.data = 0;	/* XXX */
+			if (copy_to_user(useraddr, &edata, sizeof edata))
+				return -EFAULT;
+			return 0;
+		}
+		/* set message-level */
+	case ETHTOOL_SMSGLVL:{
+			struct ethtool_value edata;
+			if (copy_from_user(&edata, useraddr, sizeof edata))
+				return -EFAULT;
+/* debug = edata.data; *//* XXX */
+			return 0;
+		}
+	}
+	return -EOPNOTSUPP;
+}
+
+static int
+mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+#ifdef CONFIG_FEC_USE_MDIO_NOT_YET_XXX
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data;
+	int phy = dev->base_addr & 0x1f;
+#endif
+	int retval;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		retval = mpc52xx_netdev_ethtool_ioctl(
+					dev, (void *) rq->ifr_data);
+		break;
+
+#ifdef CONFIG_FEC_USE_MDIO_NOT_YET_XXX
+	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
+	case SIOCDEVPRIVATE:	/* for binary compat, remove in 2.5 */
+		data->phy_id = phy;
+		/* Fall through */
+
+	case SIOCGMIIREG:	/* Read MII PHY register. */
+	case SIOCDEVPRIVATE + 1:	/* for binary compat, remove in 2.5 */
+		data->val_out =
+			mpc52xx_mdio_read(dev, data->phy_id&0x1f,
+				data->reg_num&0x1f);
+		retval = 0;
+		break;
+
+	case SIOCSMIIREG:	/* Write MII PHY register. */
+	case SIOCDEVPRIVATE + 2:	/* for binary compat, remove in 2.5 */
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+		} else {
+			mdio_write(dev, data->phy_id & 0x1f,
+				data->reg_num & 0x1f, data->val_in);
+			retval = 0;
+		}
+		break;
+#endif
+
+	default:
+		retval = -EOPNOTSUPP;
+		break;
+	}
+	return retval;
+}
+
+static void __init
+mpc52xx_fec_str2mac(char *str, unsigned char *mac)
+{
+	int i;
+	u64 val64;
+
+	val64 = simple_strtoull(str, NULL, 16);
+
+	for (i = 0; i < 6; i++)
+		mac[5-i] = val64 >> (i*8);
+}
+
+static int __init
+mpc52xx_fec_mac_setup(char *mac_address)
+{
+	mpc52xx_fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
+	return 0;
+}
+
+__setup("mpc52xx_mac=", mpc52xx_fec_mac_setup);
+
+static int __init
+mpc52xx_fec_init(void)
+{
+	struct mpc52xx_fec *fec;
+	struct net_device *dev;
+	struct mpc52xx_fec_priv *priv;
+
+	dev = alloc_etherdev(sizeof(struct mpc52xx_fec_priv));
+	if (!dev)
+		return -EIO;
+
+	mpc52xx_fec_dev = dev;
+	priv = (struct mpc52xx_fec_priv *)dev->priv;
+
+	priv->fec = fec = (struct mpc52xx_fec *)ioremap(MPC52xx_PA(MPC52xx_FEC_OFFSET), MPC52xx_FEC_SIZE);
+	priv->gpio = (struct mpc52xx_gpio *)MPC52xx_PA(MPC52xx_GPIO_OFFSET);
+	priv->sdma = (struct mpc52xx_sdma *)MPC52xx_PA(MPC52xx_SDMA_OFFSET);
+
+	spin_lock_init(&priv->lock);
+	dev->open		= mpc52xx_fec_open;
+	dev->stop		= mpc52xx_fec_close;
+	dev->hard_start_xmit	= mpc52xx_fec_hard_start_xmit;
+	dev->do_ioctl		= mpc52xx_fec_ioctl;
+	dev->get_stats		= mpc52xx_fec_get_stats;
+	dev->set_mac_address	= mpc52xx_fec_set_mac_address;
+	dev->set_multicast_list = mpc52xx_fec_set_multicast_list;
+
+	dev->tx_timeout		= mpc52xx_fec_tx_timeout;
+	dev->watchdog_timeo	= MPC52xx_FEC_WATCHDOG_TIMEOUT; 
+	dev->flags &= ~IFF_RUNNING;
+
+#ifdef CONFIG_NET_FASTROUTE
+	dev->accept_fastpath = mpc52xx_fec_accept_fastpath;
+#endif
+	if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
+		memcpy(dev->dev_addr, mpc52xx_fec_mac_addr, 6);
+	else {
+		*(u32 *)&dev->dev_addr[0] = in_be32(&fec->paddr1);
+		*(u16 *)&dev->dev_addr[4] = in_be16((u16*)&fec->paddr2);
+	}
+
+
+	/*
+	 * Read MIB counters in order to reset them,
+	 * then zero all the stats fields in memory
+	 */
+	mpc52xx_fec_update_stat(dev);
+
+	register_netdev(dev);
+	return 0;
+}
+
+static void __exit
+mpc52xx_fec_uninit(void)
+{
+	struct net_device *dev = mpc52xx_fec_dev;
+	unregister_netdev(dev);
+	kfree(dev->priv);
+	dev->priv = NULL;
+}
+
+static int __init
+mpc52xx_fec_module_init(void)
+{
+	return mpc52xx_fec_init();
+}
+
+static void __exit
+mpc52xx_fec_module_exit(void)
+{
+	mpc52xx_fec_uninit();
+}
+
+module_init(mpc52xx_fec_module_init);
+module_exit(mpc52xx_fec_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for Motorola MPC52xx FEC");
diff --git a/drivers/net/fec_mpc52xx/fec.h b/drivers/net/fec_mpc52xx/fec.h
new file mode 100644
index 0000000..364b871
--- /dev/null
+++ b/drivers/net/fec_mpc52xx/fec.h
@@ -0,0 +1,402 @@
+
+/*
+ * arch/ppc/5xxx_io/fec.h
+ *
+ * Header file for the MPC5xxx Fast Ethernet Controller driver
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * Copyright 2003 MontaVista Software
+ *
+ * 2003 (c) MontaVista, Software, Inc.  This file is licensed under the terms
+ * of the GNU General Public License version 2.  This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#ifndef PPC_52XX_IO_FEC_H
+#define PPC_52XX_IO_FEC_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/skbuff.h>
+#include <asm/mpc52xx.h>
+#include <bestcomm_api.h>
+
+/* Tunable constants */
+#define MPC52xx_FEC_RECV_BUFFER_SIZE	1518	/* max receive packet size */
+#define MPC52xx_FEC_TBD_NUM   		64	/* max transmit packets */
+#define MPC52xx_FEC_RBD_NUM  		64	/* max receive packets */
+
+struct mpc52xx_fec {
+	volatile u32 fec_id;			/* FEC + 0x000 */
+	volatile u32 ievent;			/* FEC + 0x004 */
+	volatile u32 imask;			/* FEC + 0x008 */
+
+	volatile u32 reserved0[1];		/* FEC + 0x00C */
+	volatile u32 r_des_active;		/* FEC + 0x010 */
+	volatile u32 x_des_active;		/* FEC + 0x014 */
+	volatile u32 r_des_active_cl;		/* FEC + 0x018 */
+	volatile u32 x_des_active_cl;		/* FEC + 0x01C */
+	volatile u32 ivent_set;			/* FEC + 0x020 */
+	volatile u32 ecntrl;			/* FEC + 0x024 */
+
+	volatile u32 reserved1[6];		/* FEC + 0x028-03C */
+	volatile u32 mii_data;			/* FEC + 0x040 */
+	volatile u32 mii_speed;			/* FEC + 0x044 */
+	volatile u32 mii_status;		/* FEC + 0x048 */
+
+	volatile u32 reserved2[5];		/* FEC + 0x04C-05C */
+	volatile u32 mib_data;			/* FEC + 0x060 */
+	volatile u32 mib_control;		/* FEC + 0x064 */
+
+	volatile u32 reserved3[6];		/* FEC + 0x068-7C */
+	volatile u32 r_activate;		/* FEC + 0x080 */
+	volatile u32 r_cntrl;			/* FEC + 0x084 */
+	volatile u32 r_hash;			/* FEC + 0x088 */
+	volatile u32 r_data;			/* FEC + 0x08C */
+	volatile u32 ar_done;			/* FEC + 0x090 */
+	volatile u32 r_test;			/* FEC + 0x094 */
+	volatile u32 r_mib;			/* FEC + 0x098 */
+	volatile u32 r_da_low;			/* FEC + 0x09C */
+	volatile u32 r_da_high;			/* FEC + 0x0A0 */
+
+	volatile u32 reserved4[7];		/* FEC + 0x0A4-0BC */
+	volatile u32 x_activate;		/* FEC + 0x0C0 */
+	volatile u32 x_cntrl;			/* FEC + 0x0C4 */
+	volatile u32 backoff;			/* FEC + 0x0C8 */
+	volatile u32 x_data;			/* FEC + 0x0CC */
+	volatile u32 x_status;			/* FEC + 0x0D0 */
+	volatile u32 x_mib;			/* FEC + 0x0D4 */
+	volatile u32 x_test;			/* FEC + 0x0D8 */
+	volatile u32 fdxfc_da1;			/* FEC + 0x0DC */
+	volatile u32 fdxfc_da2;			/* FEC + 0x0E0 */
+	volatile u32 paddr1;			/* FEC + 0x0E4 */
+	volatile u32 paddr2;			/* FEC + 0x0E8 */
+	volatile u32 op_pause;			/* FEC + 0x0EC */
+
+	volatile u32 reserved5[4];		/* FEC + 0x0F0-0FC */
+	volatile u32 instr_reg;			/* FEC + 0x100 */
+	volatile u32 context_reg;		/* FEC + 0x104 */
+	volatile u32 test_cntrl;		/* FEC + 0x108 */
+	volatile u32 acc_reg;			/* FEC + 0x10C */
+	volatile u32 ones;			/* FEC + 0x110 */
+	volatile u32 zeros;			/* FEC + 0x114 */
+	volatile u32 iaddr1;			/* FEC + 0x118 */
+	volatile u32 iaddr2;			/* FEC + 0x11C */
+	volatile u32 gaddr1;			/* FEC + 0x120 */
+	volatile u32 gaddr2;			/* FEC + 0x124 */
+	volatile u32 random;			/* FEC + 0x128 */
+	volatile u32 rand1;			/* FEC + 0x12C */
+	volatile u32 tmp;			/* FEC + 0x130 */
+
+	volatile u32 reserved6[3];		/* FEC + 0x134-13C */
+	volatile u32 fifo_id;			/* FEC + 0x140 */
+	volatile u32 x_wmrk;			/* FEC + 0x144 */
+	volatile u32 fcntrl;			/* FEC + 0x148 */
+	volatile u32 r_bound;			/* FEC + 0x14C */
+	volatile u32 r_fstart;			/* FEC + 0x150 */
+	volatile u32 r_count;			/* FEC + 0x154 */
+	volatile u32 r_lag;			/* FEC + 0x158 */
+	volatile u32 r_read;			/* FEC + 0x15C */
+	volatile u32 r_write;			/* FEC + 0x160 */
+	volatile u32 x_count;			/* FEC + 0x164 */
+	volatile u32 x_lag;			/* FEC + 0x168 */
+	volatile u32 x_retry;			/* FEC + 0x16C */
+	volatile u32 x_write;			/* FEC + 0x170 */
+	volatile u32 x_read;			/* FEC + 0x174 */
+
+	volatile u32 reserved7[2];		/* FEC + 0x178-17C */
+	volatile u32 fm_cntrl;			/* FEC + 0x180 */
+	volatile u32 rfifo_data;		/* FEC + 0x184 */
+	volatile u32 rfifo_status;		/* FEC + 0x188 */
+	volatile u32 rfifo_cntrl;		/* FEC + 0x18C */
+	volatile u32 rfifo_lrf_ptr;		/* FEC + 0x190 */
+	volatile u32 rfifo_lwf_ptr;		/* FEC + 0x194 */
+	volatile u32 rfifo_alarm;		/* FEC + 0x198 */
+	volatile u32 rfifo_rdptr;		/* FEC + 0x19C */
+	volatile u32 rfifo_wrptr;		/* FEC + 0x1A0 */
+	volatile u32 tfifo_data;		/* FEC + 0x1A4 */
+	volatile u32 tfifo_status;		/* FEC + 0x1A8 */
+	volatile u32 tfifo_cntrl;		/* FEC + 0x1AC */
+	volatile u32 tfifo_lrf_ptr;		/* FEC + 0x1B0 */
+	volatile u32 tfifo_lwf_ptr;		/* FEC + 0x1B4 */
+	volatile u32 tfifo_alarm;		/* FEC + 0x1B8 */
+	volatile u32 tfifo_rdptr;		/* FEC + 0x1BC */
+	volatile u32 tfifo_wrptr;		/* FEC + 0x1C0 */
+
+	volatile u32 reset_cntrl;		/* FEC + 0x1C4 */
+	volatile u32 xmit_fsm;			/* FEC + 0x1C8 */
+
+	volatile u32 reserved8[3];		/* FEC + 0x1CC-1D4 */
+	volatile u32 rdes_data0;		/* FEC + 0x1D8 */
+	volatile u32 rdes_data1;		/* FEC + 0x1DC */
+	volatile u32 r_length;			/* FEC + 0x1E0 */
+	volatile u32 x_length;			/* FEC + 0x1E4 */
+	volatile u32 x_addr;			/* FEC + 0x1E8 */
+	volatile u32 cdes_data;			/* FEC + 0x1EC */
+	volatile u32 status;			/* FEC + 0x1F0 */
+	volatile u32 dma_control;		/* FEC + 0x1F4 */
+	volatile u32 des_cmnd;			/* FEC + 0x1F8 */
+	volatile u32 data;			/* FEC + 0x1FC */
+
+	volatile u32 rmon_t_drop;		/* FEC + 0x200 */
+	volatile u32 rmon_t_packets;		/* FEC + 0x204 */
+	volatile u32 rmon_t_bc_pkt;		/* FEC + 0x208 */
+	volatile u32 rmon_t_mc_pkt;		/* FEC + 0x20C */
+	volatile u32 rmon_t_crc_align;		/* FEC + 0x210 */
+	volatile u32 rmon_t_undersize;		/* FEC + 0x214 */
+	volatile u32 rmon_t_oversize;		/* FEC + 0x218 */
+	volatile u32 rmon_t_frag;		/* FEC + 0x21C */
+	volatile u32 rmon_t_jab;		/* FEC + 0x220 */
+	volatile u32 rmon_t_col;		/* FEC + 0x224 */
+	volatile u32 rmon_t_p64;		/* FEC + 0x228 */
+	volatile u32 rmon_t_p65to127;		/* FEC + 0x22C */
+	volatile u32 rmon_t_p128to255;		/* FEC + 0x230 */
+	volatile u32 rmon_t_p256to511;		/* FEC + 0x234 */
+	volatile u32 rmon_t_p512to1023;		/* FEC + 0x238 */
+	volatile u32 rmon_t_p1024to2047;	/* FEC + 0x23C */
+	volatile u32 rmon_t_p_gte2048;		/* FEC + 0x240 */
+	volatile u32 rmon_t_octets;		/* FEC + 0x244 */
+	volatile u32 ieee_t_drop;		/* FEC + 0x248 */
+	volatile u32 ieee_t_frame_ok;		/* FEC + 0x24C */
+	volatile u32 ieee_t_1col;		/* FEC + 0x250 */
+	volatile u32 ieee_t_mcol;		/* FEC + 0x254 */
+	volatile u32 ieee_t_def;		/* FEC + 0x258 */
+	volatile u32 ieee_t_lcol;		/* FEC + 0x25C */
+	volatile u32 ieee_t_excol;		/* FEC + 0x260 */
+	volatile u32 ieee_t_macerr;		/* FEC + 0x264 */
+	volatile u32 ieee_t_cserr;		/* FEC + 0x268 */
+	volatile u32 ieee_t_sqe;		/* FEC + 0x26C */
+	volatile u32 t_fdxfc;			/* FEC + 0x270 */
+	volatile u32 ieee_t_octets_ok;		/* FEC + 0x274 */
+
+	volatile u32 reserved9[2];		/* FEC + 0x278-27C */
+	volatile u32 rmon_r_drop;		/* FEC + 0x280 */
+	volatile u32 rmon_r_packets;		/* FEC + 0x284 */
+	volatile u32 rmon_r_bc_pkt;		/* FEC + 0x288 */
+	volatile u32 rmon_r_mc_pkt;		/* FEC + 0x28C */
+	volatile u32 rmon_r_crc_align;		/* FEC + 0x290 */
+	volatile u32 rmon_r_undersize;		/* FEC + 0x294 */
+	volatile u32 rmon_r_oversize;		/* FEC + 0x298 */
+	volatile u32 rmon_r_frag;		/* FEC + 0x29C */
+	volatile u32 rmon_r_jab;		/* FEC + 0x2A0 */
+
+	volatile u32 rmon_r_resvd_0;		/* FEC + 0x2A4 */
+
+	volatile u32 rmon_r_p64;		/* FEC + 0x2A8 */
+	volatile u32 rmon_r_p65to127;		/* FEC + 0x2AC */
+	volatile u32 rmon_r_p128to255;		/* FEC + 0x2B0 */
+	volatile u32 rmon_r_p256to511;		/* FEC + 0x2B4 */
+	volatile u32 rmon_r_p512to1023;		/* FEC + 0x2B8 */
+	volatile u32 rmon_r_p1024to2047;	/* FEC + 0x2BC */
+	volatile u32 rmon_r_p_gte2048;		/* FEC + 0x2C0 */
+	volatile u32 rmon_r_octets;		/* FEC + 0x2C4 */
+	volatile u32 ieee_r_drop;		/* FEC + 0x2C8 */
+	volatile u32 ieee_r_frame_ok;		/* FEC + 0x2CC */
+	volatile u32 ieee_r_crc;		/* FEC + 0x2D0 */
+	volatile u32 ieee_r_align;		/* FEC + 0x2D4 */
+	volatile u32 r_macerr;			/* FEC + 0x2D8 */
+	volatile u32 r_fdxfc;			/* FEC + 0x2DC */
+	volatile u32 ieee_r_octets_ok;		/* FEC + 0x2E0 */
+
+	volatile u32 reserved10[6];		/* FEC + 0x2E4-2FC */
+
+	volatile u32 reserved11[64];		/* FEC + 0x300-3FF */
+};
+
+#define MPC52xx_FEC_MIB_DISABLE			0x80000000
+
+#define MPC52xx_FEC_IEVENT_HBERR		0x80000000
+#define MPC52xx_FEC_IEVENT_BABR			0x40000000
+#define MPC52xx_FEC_IEVENT_BABT			0x20000000
+#define MPC52xx_FEC_IEVENT_GRA			0x10000000
+#define MPC52xx_FEC_IEVENT_TFINT		0x08000000
+#define MPC52xx_FEC_IEVENT_MII			0x00800000
+#define MPC52xx_FEC_IEVENT_LATE_COL		0x00200000
+#define MPC52xx_FEC_IEVENT_COL_RETRY_LIM	0x00100000
+#define MPC52xx_FEC_IEVENT_XFIFO_UN		0x00080000
+#define MPC52xx_FEC_IEVENT_XFIFO_ERROR		0x00040000
+#define MPC52xx_FEC_IEVENT_RFIFO_ERROR		0x00020000
+
+#define MPC52xx_FEC_IMASK_HBERR			0x80000000
+#define MPC52xx_FEC_IMASK_BABR			0x40000000
+#define MPC52xx_FEC_IMASK_BABT			0x20000000
+#define MPC52xx_FEC_IMASK_GRA			0x10000000
+#define MPC52xx_FEC_IMASK_MII			0x00800000
+#define MPC52xx_FEC_IMASK_LATE_COL		0x00200000
+#define MPC52xx_FEC_IMASK_COL_RETRY_LIM		0x00100000
+#define MPC52xx_FEC_IMASK_XFIFO_UN		0x00080000
+#define MPC52xx_FEC_IMASK_XFIFO_ERROR		0x00040000
+#define MPC52xx_FEC_IMASK_RFIFO_ERROR		0x00020000
+
+#define MPC52xx_FEC_RCNTRL_MAX_FL_SHIFT		16
+#define MPC52xx_FEC_RCNTRL_LOOP			0x01
+#define MPC52xx_FEC_RCNTRL_DRT			0x02
+#define MPC52xx_FEC_RCNTRL_MII_MODE		0x04
+#define MPC52xx_FEC_RCNTRL_PROM			0x08
+#define MPC52xx_FEC_RCNTRL_BC_REJ		0x10
+#define MPC52xx_FEC_RCNTRL_FCE			0x20
+
+#define MPC52xx_FEC_TCNTRL_GTS			0x00000001
+#define MPC52xx_FEC_TCNTRL_HBC			0x00000002
+#define MPC52xx_FEC_TCNTRL_FDEN			0x00000004
+#define MPC52xx_FEC_TCNTRL_TFC_PAUSE		0x00000008
+#define MPC52xx_FEC_TCNTRL_RFC_PAUSE		0x00000010
+
+#define MPC52xx_FEC_ECNTRL_RESET		0x00000001
+#define MPC52xx_FEC_ECNTRL_ETHER_EN		0x00000002
+
+#define MPC52xx_FEC_RESET_DELAY			50 /* uS */
+
+
+/* Receive & Transmit Buffer Descriptor definitions */
+struct mpc52xx_fec_bd {
+	volatile u32 status;
+	volatile u32 data;
+};
+
+/* Receive data buffer format */
+struct mpc52xx_rbuf {
+	u8 data[MPC52xx_FEC_RECV_BUFFER_SIZE];
+};
+
+struct fec_queue {
+	volatile struct mpc52xx_fec_bd *bd_base;
+	struct sk_buff **skb_base;
+	u16 last_index;
+	u16 start_index;
+	u16 finish_index;
+};
+
+#ifdef CONFIG_FEC_USE_MDIO 
+#define MII_ADVERTISE_HALF	(ADVERTISE_100HALF | ADVERTISE_10HALF | \
+				 ADVERTISE_CSMA)
+
+#define MII_ADVERTISE_ALL	(ADVERTISE_100FULL | ADVERTISE_10FULL | \
+				 MII_ADVERTISE_HALF)
+#ifdef PHY_INTERRUPT
+#define MII_ADVERTISE_DEFAULT   MII_ADVERTISE_ALL
+#else
+#define MII_ADVERTISE_DEFAULT   MII_ADVERTISE_HALF
+#endif
+
+typedef struct {
+	uint mii_data;
+	void (*funct)(uint mii_reg, struct net_device *dev, uint data);
+} phy_cmd_t;
+
+typedef struct {
+	uint id;
+	char *name;
+
+	const phy_cmd_t *config;
+	const phy_cmd_t *startup;
+	const phy_cmd_t *ack_int;
+	const phy_cmd_t *shutdown;
+} phy_info_t;
+#endif	/* CONFIG_FEC_USE_MDIO */
+
+struct mpc52xx_fec_priv {
+	int full_duplex;
+	int tx_full;
+	int r_tasknum;
+	int t_tasknum;
+	int r_irq;
+	int t_irq;
+	u32 last_transmit_time;
+	u32 last_receive_time;
+	struct mpc52xx_fec *fec;
+	struct mpc52xx_sram_fec *sram;
+	struct mpc52xx_gpio *gpio;
+	struct mpc52xx_sdma *sdma;
+	struct fec_queue r_queue;
+	struct sk_buff *rskb[MPC52xx_FEC_RBD_NUM];
+	struct fec_queue t_queue;
+	struct sk_buff *tskb[MPC52xx_FEC_TBD_NUM];
+	spinlock_t lock;
+	unsigned long open_time;
+	struct net_device_stats stats;
+#ifdef CONFIG_FEC_USE_MDIO
+	uint phy_id;
+	uint phy_id_done;
+	uint phy_status;
+	uint phy_speed;
+	phy_info_t *phy;
+	struct work_struct phy_task;
+	volatile uint sequence_done;
+	uint link;
+	uint phy_addr;
+
+	struct timer_list phy_timer_list;
+	u16 old_status;
+#endif	/* CONFIG_FEC_USE_MDIO */
+};
+
+struct mpc52xx_sram_fec {
+	volatile struct mpc52xx_fec_bd tbd[MPC52xx_FEC_TBD_NUM];
+	volatile struct mpc52xx_fec_bd rbd[MPC52xx_FEC_RBD_NUM];
+};
+
+#define MPC52xx_FEC_RBD_READY	0x40000000
+#define MPC52xx_FEC_RBD_RFD	0x08000000	/* receive frame done */
+
+#define MPC52xx_FEC_RBD_INIT	MPC52xx_FEC_RBD_READY
+
+#define MPC52xx_FEC_TBD_READY	0x40000000
+#define MPC52xx_FEC_TBD_TFD	0x08000000	/* transmit frame done */
+#define MPC52xx_FEC_TBD_INT	0x04000000	/* Interrupt */
+
+#define MPC52xx_FEC_TBD_INIT	(MPC52xx_FEC_TBD_INT | MPC52xx_FEC_TBD_TFD | \
+				 MPC52xx_FEC_TBD_READY)
+
+
+
+/* MII-related definitions */
+#define MPC52xx_FEC_MII_DATA_ST		0x40000000	/* Start frame */
+#define MPC52xx_FEC_MII_DATA_OP_RD	0x20000000	/* Perform read */
+#define MPC52xx_FEC_MII_DATA_OP_WR	0x10000000	/* Perform write */
+#define MPC52xx_FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address mask */
+#define MPC52xx_FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register mask */
+#define MPC52xx_FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define MPC52xx_FEC_MII_DATA_DATAMSK	0x00000fff	/* PHY data mask */
+
+#define MPC52xx_FEC_MII_DATA_RA_SHIFT	0x12		/* MII reg addr bits */
+#define MPC52xx_FEC_MII_DATA_PA_SHIFT	0x17		/* MII PHY addr bits */
+
+#define MPC52xx_FEC_MII_SPEED		(5 * 2)
+
+const char mpc52xx_fec_name[] = "eth0";
+
+struct mibCounters {
+	unsigned int byteReceived;
+	unsigned int byteSent;
+	unsigned int framesReceived;
+	unsigned int framesSent;
+	unsigned int totalByteReceived;
+	unsigned int totalFramesReceived;
+	unsigned int broadcastFramesReceived;
+	unsigned int multicastFramesReceived;
+	unsigned int cRCError;
+	unsigned int oversizeFrames;
+	unsigned int fragments;
+	unsigned int jabber;
+	unsigned int collision;
+	unsigned int lateCollision;
+	unsigned int frames64;
+	unsigned int frames65_127;
+	unsigned int frames128_255;
+	unsigned int frames256_511;
+	unsigned int frames512_1023;
+	unsigned int frames1024_MaxSize;
+	unsigned int macRxError;
+	unsigned int droppedFrames;
+	unsigned int outMulticastFrames;
+	unsigned int outBroadcastFrames;
+	unsigned int undersizeFrames;
+};
+
+#define MPC52xx_FEC_WATCHDOG_TIMEOUT  ((400*HZ)/1000)
+
+#endif	/* PPC_52XX_IO_FEC_H */
diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
index a055e07..ce6ceb5 100644
--- a/include/asm-ppc/mpc52xx.h
+++ b/include/asm-ppc/mpc52xx.h
@@ -100,6 +100,9 @@ enum ppc_sys_devices {
 #define MPC52xx_XLB_SIZE		0x100
 #define MPC52xx_PSCx_OFFSET(x)		(((x)!=6)?(0x1e00+((x)<<9)):0x2c00)
 #define MPC52xx_PSC_SIZE		0x0a0
+#define MPC52xx_FEC_OFFSET		0x3000
+#define MPC52xx_FEC_SIZE		0x800
+
 
 /* SRAM used for SDMA */
 #define MPC52xx_SRAM_OFFSET		0x8000
-- 
1.1.3

^ permalink raw reply related

* Re: Yosemite/440EP why are readl()/ioread32() setup to readlittle-endian?
From: Matt Porter @ 2006-02-02 18:16 UTC (permalink / raw)
  To: Jenkins, Clive, Peter Korsgaard, Kumar Gala, linuxppc-embedded
In-Reply-To: <20060202174504.GE12810@gate.ebshome.net>

On Thu, Feb 02, 2006 at 09:45:04AM -0800, Eugene Surovegin wrote:
> On Thu, Feb 02, 2006 at 07:37:01AM -0700, Matt Porter wrote:
> > I mentioned the BE iomap variants that are being used on some non-pci
> > parisc devices already. I'll give a partial example of something that
> > is non-pci yet "arch-independent".
> > 
> > Take a non-pci EHCI core (yes, I know it's little endian by definition
> > but suspend reality for a second).  You can create an arch-independent
> > EHCI driver that uses the platform bus by using the iomap accessors.
> > Since these cores are licensed every day by XYZ startups for their
> > latest "gee-whiz" SoC, it reasons that you'll see the same core on
> > multiple licensable SoC architectures. I've seen one such thing
> > on MIPS.
> > 
> > We also know that major semiconductor companies do the same thing
> > for their peripherals in some cases. They're just as willing to
> > buy somebody else's USB core, for example.  So, having a BE
> > non-pci device cross platform isn't a stretch.
> > 
> > Take a look at drivers/scsi/53c700.{c,h}. That generic driver
> > is why BE iomap accessors were added. It's in the process of
> > being shared between parisc and m68k.
> > 
> 
> Matt, my problem with this approach is that it repeats the same 
> old mistakes but in "BE-mode", e.g. _assuming_ some access mode and 
> hard-coding it into the driver. I fail to see how assuming big-endian 
> is any better than assuming little-endian in this case. And this is 
> not _portable_ in my book, no matter what some people want me to 
> believe.
> 
> This fails miserably when for example you have a bus which does byte 
> swaps in every half-word. And yes, I have such device on my table and 
> I have to port PCMCIA/PCI drivers to this SoC :).

Yuck. But a good example that there are always ill-behaved exceptions.

> Here is how inb looks like:
> 
> static inline u8 fpi_inb(unsigned long port)
> {
>     port ^= 1;
>     return inb(port);
> }
> 
> IMO, truly portable and driver independent I/O accessors should be 
> implemented as a function pointers on per-bus (at least) basis which 
> can be overridden by arch or board code. In this case we can get rid 
> of "ugly" ifdefs in driver code :).

There are a ton of reasons for this too, but there's been resistance
in the past to anything adding an additional dereference to the ia32
case.  I think there's been some proposals to get around this and
maybe even some small level of acceptance. However, since the server
folks don't need it, it's slow going to get such a major change pushed
through.

FWIW, some Xscale IXPs could use the per-bus pointer accessors to
manage the some floating I/O windows more cleanly as well. RapidIO
has some use for it too. It's not just byte swapping at least.

You could drive this change, you know. :)

-Matt

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setup to readlittle-endian?
From: Eugene Surovegin @ 2006-02-02 17:45 UTC (permalink / raw)
  To: Matt Porter; +Cc: linuxppc-embedded, Jenkins, Clive
In-Reply-To: <20060202073700.B27740@cox.net>

On Thu, Feb 02, 2006 at 07:37:01AM -0700, Matt Porter wrote:
> I mentioned the BE iomap variants that are being used on some non-pci
> parisc devices already. I'll give a partial example of something that
> is non-pci yet "arch-independent".
> 
> Take a non-pci EHCI core (yes, I know it's little endian by definition
> but suspend reality for a second).  You can create an arch-independent
> EHCI driver that uses the platform bus by using the iomap accessors.
> Since these cores are licensed every day by XYZ startups for their
> latest "gee-whiz" SoC, it reasons that you'll see the same core on
> multiple licensable SoC architectures. I've seen one such thing
> on MIPS.
> 
> We also know that major semiconductor companies do the same thing
> for their peripherals in some cases. They're just as willing to
> buy somebody else's USB core, for example.  So, having a BE
> non-pci device cross platform isn't a stretch.
> 
> Take a look at drivers/scsi/53c700.{c,h}. That generic driver
> is why BE iomap accessors were added. It's in the process of
> being shared between parisc and m68k.
> 

Matt, my problem with this approach is that it repeats the same 
old mistakes but in "BE-mode", e.g. _assuming_ some access mode and 
hard-coding it into the driver. I fail to see how assuming big-endian 
is any better than assuming little-endian in this case. And this is 
not _portable_ in my book, no matter what some people want me to 
believe.

This fails miserably when for example you have a bus which does byte 
swaps in every half-word. And yes, I have such device on my table and 
I have to port PCMCIA/PCI drivers to this SoC :).

Here is how inb looks like:

static inline u8 fpi_inb(unsigned long port)
{
    port ^= 1;
    return inb(port);
}

IMO, truly portable and driver independent I/O accessors should be 
implemented as a function pointers on per-bus (at least) basis which 
can be overridden by arch or board code. In this case we can get rid 
of "ugly" ifdefs in driver code :).

-- 
Eugene

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setup to readlittle-endian?
From: Dale Farnsworth @ 2006-02-02 17:34 UTC (permalink / raw)
  To: Linuxppc-embedded
In-Reply-To: <20060202090827.GA12810@gate.ebshome.net>

In article <20060202090827.GA12810@gate.ebshome.net> you write:
> On Thu, Feb 02, 2006 at 09:09:17AM +0100, Peter Korsgaard wrote:
> > On 2/2/06, Kumar Gala <galak@kernel.crashing.org> wrote:
> > > > What is the preferred way of accessing non-PCI devices then? Direct
> > > > pointer access?
> > >
> > > No direct pointer access is bad. On PPC You can use
> > > in_be{8,16,32}/out_be{8,16,32}
> > 
> > What about arch independent drivers? Are there any generic approach
> > for this or do you have to stick to ugly #ifdefs to decide between
> > in_be32/inl ?
> 
> I'm curious, could you give an example of such arch independent 
> driver?

Such #ifdefs are found in drivers/net/smc91x.h

-Dale

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setuptoreadlittle-endian?
From: Eugene Surovegin @ 2006-02-02 17:16 UTC (permalink / raw)
  To: Jenkins, Clive; +Cc: linuxppc-embedded
In-Reply-To: <35786B99AB3FDC45A8215724617919736D921E@gbrwgceumf01.eu.xerox.net>

On Thu, Feb 02, 2006 at 11:26:22AM -0000, Jenkins, Clive wrote:
> Regardless of what standards or hardware might exist, I would be
> happy if Linux provided alternatives to readl()... that converted
> between big-endian and cpu-endian, so that I could write in my
> driver, for example:
> 
> static inline my_readl(...)
> {
> #if (my interconnect is PCI or other little-endian)
>     return(readl(...));
> #else
>     return(readl_be(...));
> #endif
> }
> 
> That must make my driver more portable in future circumstances

Huh?

If you re-read this thread, you'll notice that I was responding to 
e-mail where original poster did NOT want to do exactly this in his 
driver. But you are suggesting what we were discussing on how to  
_avoid_. I'm really confused, what is your point?

What I was talking, in short, that if we _really_ want generic non-PCI 
accessors, we need something similar to the way IDE layer defines its 
I/O operations - bunch of per-bus/device function pointers which can 
be overridden depending on arch, bus and the way peripheral is wired.

-- 
Eugene

^ permalink raw reply

* Is /sys/.../power/state supported ?
From: Giuliano Pochini @ 2006-02-02 15:45 UTC (permalink / raw)
  To: linuxppc-dev


echo 3 > /sys/pci.../power/state  does nothing on my machine.
I have a PMac dual-G4 MDD, linux 2.6.14 and of course
CONFIG_PM and debug are enabled. It writes nothing in the
logs and the value it reads from any device/power/state is
always 0, no matter what I wrote into it. I wonder if it is
supposed to work, or if it not supported yet... or maybe if
I'm missing something.


--
Giuliano.

^ permalink raw reply

* Re: Accessing the CPM2 on an MPC82xx : CPM_MAP_ADDR or cpm2_immr ?
From: Laurent Pinchart @ 2006-02-02 15:42 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-embedded
In-Reply-To: <20060202170753.2a805189@vitb.ru.mvista.com>

> > I noticed that the CPM2 module is accessed both through CPM_MAP_ADDR
> > (physical address) and cpm2_immr (ioremap()ed address). For instance, the
> > fec_enet driver configures the IO ports using (cpm2_map_t*)CPM_MAP_ADDR.
>
> Mentioned driver is deprecated.

It has been replaced by drivers/net/fs_enet, right ? The new driver doesn't 
support the LXT971/LXT971A PHY chipsets yet, so I'm still using the old one.

> > What's the correct way to access the CPM2 module ? Does ioremap() map
> > CPM_MAP_ADDR to itself so that both ways are correct ?
>
> Even direct cpm2_immr usage is not a good thing, but I cannot tell more
> without knowing your concerns. Can you please describe what you are
> planning to implement, prolly we can advice how to do that proper way.

I'm currently just hacking IDMA transfers to make sure the signals we plan to 
use on a custom design work as expected. I will later work on the USB host 
controller driver.

The new fs_enet driver internally maps CPM_MAP_ADDR. Should every driver 
create an internal CPM mapping ? Why was the old fec_enet driver able to 
access the CPM through CPM_MAP_ADDR without ioremap()ing it first ?

Laurent Pinchart

^ permalink raw reply

* RE: [patch 10/44] generic fls64()
From: Rune Torgersen @ 2006-02-02 15:05 UTC (permalink / raw)
  To: Akinobu Mita, linux-kernel
  Cc: linux-mips, linux-ia64, Ian Molton, David Howells, linuxppc-dev,
	Greg Ungerer, sparclinux, Miles Bader, Linus Torvalds,
	Yoshinori Sato, Hirokazu Takata, linuxsh-dev, linux-m68k,
	Ivan Kokshaysky, Richard Henderson, Chris Zankel, dev-etrax,
	ultralinux, Andi Kleen, linuxsh-shmedia-dev, linux390,
	Russell King, parisc-linux

> From: Akinobu Mita
> Sent: Wednesday, February 01, 2006 03:03
> +static inline int fls64(__u64 x)
> +{
> +	__u32 h =3D x >> 32;
> +	if (h)
> +		return fls(x) + 32;

Shouldn't this be return fls(h) + 32; ??
                            ^^^
> +	return fls(x);
> +}
> +
> +#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */
>=20
> --
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>=20
>=20

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setuptoreadlittle-endian?
From: Matt Porter @ 2006-02-02 14:39 UTC (permalink / raw)
  To: Jenkins, Clive; +Cc: linuxppc-embedded
In-Reply-To: <35786B99AB3FDC45A8215724617919736D921E@gbrwgceumf01.eu.xerox.net>

On Thu, Feb 02, 2006 at 11:26:22AM -0000, Jenkins, Clive wrote:
> I'm not sure all this fuss is justified in response to:
> 
> > What is the preferred way of accessing non-PCI devices then?
> > Direct pointer access?
> > Bye, Peter Korsgaard
> 
> Regardless of what standards or hardware might exist, I would be
> happy if Linux provided alternatives to readl()... that converted
> between big-endian and cpu-endian, so that I could write in my
> driver, for example:

As I pointed out, there are such alternatives. The iomap interface
provides what you need.

-Matt

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setup to readlittle-endian?
From: Matt Porter @ 2006-02-02 14:37 UTC (permalink / raw)
  To: Jenkins, Clive, Peter Korsgaard, Kumar Gala, linuxppc-embedded
In-Reply-To: <20060202094641.GB12810@gate.ebshome.net>

On Thu, Feb 02, 2006 at 01:46:41AM -0800, Eugene Surovegin wrote:
> On Thu, Feb 02, 2006 at 09:35:56AM -0000, Jenkins, Clive wrote:
> > A driver for some device that could be connected to (or plugged into)
> > a variety of different platforms of different architecture.
> > A driver for a core that could be implemented within an FPGA on
> > multiple platforms.
> 
> Well, this is all nice but I was wondering about _real_ examples.
> When you are talking about "connecting" or "plugging" you have to keep 
> in mind actual bus interconnect. So far AFAIK PCI (and derivatives) 
> are the only cross-arch bus.
> 
> So basically, you have no _real_ life examples, so I'm wondering why 
> people need this "arch-independent" non-PCI I/O accessors for 
> something which doesn't exist.
> 
> I think the reason why Linux doesn't have this stuff follows from the 
> previous paragraph.

I mentioned the BE iomap variants that are being used on some non-pci
parisc devices already. I'll give a partial example of something that
is non-pci yet "arch-independent".

Take a non-pci EHCI core (yes, I know it's little endian by definition
but suspend reality for a second).  You can create an arch-independent
EHCI driver that uses the platform bus by using the iomap accessors.
Since these cores are licensed every day by XYZ startups for their
latest "gee-whiz" SoC, it reasons that you'll see the same core on
multiple licensable SoC architectures. I've seen one such thing
on MIPS.

We also know that major semiconductor companies do the same thing
for their peripherals in some cases. They're just as willing to
buy somebody else's USB core, for example.  So, having a BE
non-pci device cross platform isn't a stretch.

Take a look at drivers/scsi/53c700.{c,h}. That generic driver
is why BE iomap accessors were added. It's in the process of
being shared between parisc and m68k.

-Matt

^ permalink raw reply

* Re: [patch 14/44] generic hweight{64,32,16,8}()
From: Gabriel Paubert @ 2006-02-02  1:26 UTC (permalink / raw)
  To: Akinobu Mita
  Cc: linux-mips, linux-m68k, linux-ia64, Ian Molton, Andi Kleen,
	David Howells, linuxppc-dev, Greg Ungerer, sparclinux,
	Miles Bader, Yoshinori Sato, Hirokazu Takata, linuxsh-dev,
	Linus Torvalds, Ivan Kokshaysky, Richard Henderson, Chris Zankel,
	dev-etrax, ultralinux, linux-kernel, linuxsh-shmedia-dev,
	linux390, Russell King, parisc-linux
In-Reply-To: <20060201090325.905071000@localhost.localdomain>

On Wed, Feb 01, 2006 at 06:02:38PM +0900, Akinobu Mita wrote:
> 
> This patch introduces the C-language equivalents of the functions below:
> 
> unsigned int hweight32(unsigned int w);
> unsigned int hweight16(unsigned int w);
> unsigned int hweight8(unsigned int w);
> unsigned long hweight64(__u64 w);
> 
> In include/asm-generic/bitops/hweight.h
> 
> This code largely copied from:
> include/linux/bitops.h
> 
> Signed-off-by: Akinobu Mita <mita@miraclelinux.com>
>  include/asm-generic/bitops/hweight.h |   54 +++++++++++++++++++++++++++++++++++
>  1 files changed, 54 insertions(+)
> 
> Index: 2.6-git/include/asm-generic/bitops/hweight.h
> ===================================================================
> --- /dev/null
> +++ 2.6-git/include/asm-generic/bitops/hweight.h
> @@ -0,0 +1,54 @@
> +#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
> +#define _ASM_GENERIC_BITOPS_HWEIGHT_H_
> +
> +#include <asm/types.h>
> +
> +/**
> + * hweightN - returns the hamming weight of a N-bit word
> + * @x: the word to weigh
> + *
> + * The Hamming Weight of a number is the total number of bits set in it.
> + */
> +
> +static inline unsigned int hweight32(unsigned int w)
> +{
> +        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
> +        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
> +        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
> +        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
> +        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
> +}


The first step can be implemented slightly better:

unsigned int res = w-((w>>1)&0x55555555);

as I found once on the web[1].

Several of the following steps can also be simplified
by omitting the masking when the result can't possibly
cause a carry to propagate too far.

This might also have a non negligible impact
on code size.


> +
> +static inline unsigned int hweight16(unsigned int w)
> +{
> +        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
> +        res = (res & 0x3333) + ((res >> 2) & 0x3333);
> +        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
> +        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
> +}
> +
> +static inline unsigned int hweight8(unsigned int w)
> +{
> +        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
> +        res = (res & 0x33) + ((res >> 2) & 0x33);
> +        return (res & 0x0F) + ((res >> 4) & 0x0F);
> +}
> +
> +static inline unsigned long hweight64(__u64 w)
> +{
> +#if BITS_PER_LONG == 32
> +	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
> +#elif BITS_PER_LONG == 64
> +	u64 res;
> +	res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
> +	res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
> +	res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
> +	res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
> +	res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
> +	return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
> +#else
> +#error BITS_PER_LONG not defined
> +#endif
> +}
> +
> +#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
>


	Regards,
	Gabriel

[1] It might be better to write the first line 

	unsigned res = w - ((w&0xaaaaaaaa)>>1);

but I can never remember what the C standard guarantess about 
right shifts values (very little IIRC). I believe that it will
work properly on all architectures that GCC supports, however,
and that it will help on many.

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setup to readlittle-endian?
From: Matt Porter @ 2006-02-02 14:21 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: linuxppc-embedded, Jenkins, Clive
In-Reply-To: <9305ca410602020009r4946d874qc52c2b27f715370f@mail.gmail.com>

On Thu, Feb 02, 2006 at 09:09:17AM +0100, Peter Korsgaard wrote:
> On 2/2/06, Kumar Gala <galak@kernel.crashing.org> wrote:
> > > What is the preferred way of accessing non-PCI devices then? Direct
> > > pointer access?
> >
> > No direct pointer access is bad. On PPC You can use
> > in_be{8,16,32}/out_be{8,16,32}
> 
> What about arch independent drivers? Are there any generic approach
> for this or do you have to stick to ugly #ifdefs to decide between
> in_be32/inl ?

ioread*be()/iowrite*be() can be used for this. Since the generic
big endian accessors became a standard thing a little while back,
all the PPC on-chip drivers should move to that. It's just a matter
of time.

-Matt

^ permalink raw reply

* Re: [CFT] Don't use ASYNC_* nor SERIAL_IO_* with serial_core
From: Hirokazu Takata @ 2006-02-02 14:10 UTC (permalink / raw)
  To: rmk+lkml; +Cc: pfg, linux-mips, takata, linux-kernel, linuxppc-dev
In-Reply-To: <20060202102721.GE5034@flint.arm.linux.org.uk>

On m32r,
  compile and boot test: OK

Thank you.

-- Takata

From: Russell King <rmk+lkml@arm.linux.org.uk>
Date: Thu, 02 Feb 2006 10:27:21 +0000
> Ping?
> 
> On Sat, Jan 21, 2006 at 09:14:07PM +0000, Russell King wrote:
> > The serial_core layer has its own definitions for these, and I'd
> > appreciate it if folk would use them instead of the old ASYNC_* and
> > SERIAL_IO_* definitions.
> > 
> > They're compatible _at the moment_ but I make no guarantees that they
> > will stay that way.  Hence, it's in your interest to ensure that you're
> > using the correct definitions.
> > 
> > MIPS, PPC seem to be the architectures which are stuck in the past on
> > this issue, as is the M32R SIO driver.
> > 
> > The ioc4_serial driver is worse.  It assumes that it can set/clear
> > ASYNC_CTS_FLOW in the uart_info flags field, which is private to
> > serial_core.  It also seems to set TTY_IO_ERROR followed by immediately
> > clearing it (pointless), and then it writes to tty->alt_speed... which
> > isn't used by the serial layer so is also pointless.
> > 
> > So, here's a patch to fix some of this crap up.  Please test and
> > enjoy - I certainly didn't.
...
> >  drivers/serial/m32r_sio.c                  |    2 +-
> >  18 files changed, 32 insertions(+), 51 deletions(-)
...
> > +++ b/arch/mips/cobalt/setup.c
> > diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
> > --- a/drivers/serial/m32r_sio.c
> > +++ b/drivers/serial/m32r_sio.c
> > @@ -80,7 +80,7 @@
> >  #include <asm/serial.h>
> >  
> >  /* Standard COM flags */
> > -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
> > +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
> >  
> >  /*
> >   * SERIAL_PORT_DFNS tells us about built-in ports that have no
> 
> -- 
> Russell King
>  Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
>  maintainer of:  2.6 Serial core
> 

^ permalink raw reply

* Re: Accessing the CPM2 on an MPC82xx : CPM_MAP_ADDR or cpm2_immr ?
From: Vitaly Bordug @ 2006-02-02 14:07 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linuxppc-embedded
In-Reply-To: <200602021458.26623.laurent.pinchart@tbox.biz>

On Thu, 2 Feb 2006 14:58:26 +0100
Laurent Pinchart <laurent.pinchart@tbox.biz> wrote:

> Hi everybody,
> 
> I noticed that the CPM2 module is accessed both through CPM_MAP_ADDR (physical 
> address) and cpm2_immr (ioremap()ed address). For instance, the fec_enet 
> driver configures the IO ports using (cpm2_map_t*)CPM_MAP_ADDR.
> 

Mentioned driver is deprecated. 
> What's the correct way to access the CPM2 module ? Does ioremap() map 
> CPM_MAP_ADDR to itself so that both ways are correct ?
> 

Even direct cpm2_immr usage is not a good thing, but I cannot tell more without knowing your concerns. Can you please describe what you are planning to implement, prolly we can advice how to do that proper way.


> Laurent Pinchart
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> 
> 


-- 
Sincerely, 
Vitaly

^ permalink raw reply

* Accessing the CPM2 on an MPC82xx : CPM_MAP_ADDR or cpm2_immr ?
From: Laurent Pinchart @ 2006-02-02 13:58 UTC (permalink / raw)
  To: linuxppc-embedded

Hi everybody,

I noticed that the CPM2 module is accessed both through CPM_MAP_ADDR (physical 
address) and cpm2_immr (ioremap()ed address). For instance, the fec_enet 
driver configures the IO ports using (cpm2_map_t*)CPM_MAP_ADDR.

What's the correct way to access the CPM2 module ? Does ioremap() map 
CPM_MAP_ADDR to itself so that both ways are correct ?

Laurent Pinchart

^ permalink raw reply

* Re: [patch 14/44] generic hweight{64,32,16,8}()
From: Akinobu Mita @ 2006-02-02 12:50 UTC (permalink / raw)
  To: Andi Kleen
  Cc: linux-mips, linux-ia64, Ian Molton, Michael Tokarev,
	David Howells, linuxppc-dev, Greg Ungerer, sparclinux,
	Miles Bader, Yoshinori Sato, Hirokazu Takata, linuxsh-dev,
	Linus Torvalds, Ivan Kokshaysky, Richard Henderson, Chris Zankel,
	dev-etrax, ultralinux, linux-m68k, linux-kernel,
	linuxsh-shmedia-dev, linux390, Russell King, parisc-linux
In-Reply-To: <200602011124.29423.ak@suse.de>

On Wed, Feb 01, 2006 at 11:24:27AM +0100, Andi Kleen wrote:
> On Wednesday 01 February 2006 10:26, Michael Tokarev wrote:
> > Andi Kleen wrote:
> > > On Wednesday 01 February 2006 10:02, Akinobu Mita wrote:
> > > 
> > >>+static inline unsigned int hweight32(unsigned int w)
> > []
> > > How large are these functions on x86? Maybe it would be better to not inline them,
> > > but put it into some C file out of line.
> > 
> > hweight8	47 bytes
> > hweight16	76 bytes
> > hweight32	97 bytes
> > hweight64	56 bytes (NOT inlining hweight32)
> > hweight64	197 bytes (inlining hweight32)
> > 
> > Those are when compiled as separate non-inlined functions,
> > with pushl %ebp and ret.
> 
> This would argue for moving them out of line.

This patch will put hweight*() into lib/hweight.c

Index: 2.6-git/include/asm-generic/bitops/hweight.h
===================================================================
--- 2.6-git.orig/include/asm-generic/bitops/hweight.h
+++ 2.6-git/include/asm-generic/bitops/hweight.h
@@ -1,54 +1,9 @@
 #ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
 #define _ASM_GENERIC_BITOPS_HWEIGHT_H_
 
-#include <asm/types.h>
-
-/**
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-static inline unsigned int hweight32(unsigned int w)
-{
-        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
-        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
-        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
-        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
-static inline unsigned int hweight16(unsigned int w)
-{
-        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
-        res = (res & 0x3333) + ((res >> 2) & 0x3333);
-        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
-        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
-}
-
-static inline unsigned int hweight8(unsigned int w)
-{
-        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
-        res = (res & 0x33) + ((res >> 2) & 0x33);
-        return (res & 0x0F) + ((res >> 4) & 0x0F);
-}
-
-static inline unsigned long hweight64(__u64 w)
-{
-#if BITS_PER_LONG == 32
-	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
-#elif BITS_PER_LONG == 64
-	u64 res;
-	res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
-	res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
-	res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
-	res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
-	res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
-	return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
-#else
-#error BITS_PER_LONG not defined
-#endif
-}
+extern unsigned int hweight32(unsigned int w);
+extern unsigned int hweight16(unsigned int w);
+extern unsigned int hweight8(unsigned int w);
+extern unsigned long hweight64(__u64 w);
 
 #endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
Index: 2.6-git/lib/Makefile
===================================================================
--- 2.6-git.orig/lib/Makefile
+++ 2.6-git/lib/Makefile
@@ -5,7 +5,7 @@
 lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
 	 bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
 	 idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \
-	 sha1.o
+	 sha1.o hweight.o
 
 lib-y	+= kobject.o kref.o kobject_uevent.o klist.o
 
Index: 2.6-git/lib/hweight.c
===================================================================
--- /dev/null
+++ 2.6-git/lib/hweight.c
@@ -0,0 +1,54 @@
+#include <linux/module.h>
+#include <asm/types.h>
+
+/**
+ * hweightN - returns the hamming weight of a N-bit word
+ * @x: the word to weigh
+ *
+ * The Hamming Weight of a number is the total number of bits set in it.
+ */
+
+unsigned int hweight32(unsigned int w)
+{
+        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+EXPORT_SYMBOL(hweight32);
+
+unsigned int hweight16(unsigned int w)
+{
+        unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+        res = (res & 0x3333) + ((res >> 2) & 0x3333);
+        res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+        return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+EXPORT_SYMBOL(hweight16);
+
+unsigned int hweight8(unsigned int w)
+{
+        unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+        res = (res & 0x33) + ((res >> 2) & 0x33);
+        return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+EXPORT_SYMBOL(hweight8);
+
+unsigned long hweight64(__u64 w)
+{
+#if BITS_PER_LONG == 32
+	return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
+#elif BITS_PER_LONG == 64
+	u64 res;
+	res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
+	res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
+	res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
+	res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
+	res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
+	return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
+#else
+#error BITS_PER_LONG not defined
+#endif
+}
+EXPORT_SYMBOL(hweight64);

^ permalink raw reply

* Re: opening the serial port from userspace application
From: Vitaly Bordug @ 2006-02-02 11:45 UTC (permalink / raw)
  To: bharathi kandimalla; +Cc: linuxppc-embedded
In-Reply-To: <20060201082419.53038.qmail@web50010.mail.yahoo.com>

On Wed, 1 Feb 2006 00:24:19 -0800 (PST)
bharathi kandimalla <bharthik2004@yahoo.com> wrote:

> Hi
> I am able to  use the serialport uart drivers  for the custom board with =
mpc860T=20
>  which are available in the kernel 2.6.13 =20
> I am getting bootup messages like this
>   ttyCPM0 at MMIO 0xfb000a80 (irq =3D 20) is a CPM UART
> ttyCPM1 at MMIO 0xfb000a90 (irq =3D 19) is a CPM UART
> ttyCPM2 at MMIO 0xfb000a00 (irq =3D 46) is a CPM UART
> ttyCPM3 at MMIO 0xfb000a20 (irq =3D 45) is a CPM UART =20

=46rom what I can see, you have misconfigured something. Dunno for certain, b=
ut 860T=20
might have 2 UARTs, when you have at least 4 enabled. Please enable in the =
kernel configuration only those which exist on your board.

>    And after getting prompt
> cd /proc/dev/    =20
> cat drivers
> /dev/tty             /dev/tty        5       0 system:/dev/tty
> /dev/console         /dev/console    5       1 system:console
> /dev/ptmx            /dev/ptmx       5       2 system
> ttyCPM               /dev/ttyCPM   204 46-49 serial
> pty_slave            /dev/pts      136 0-1048575 pty:slave
> pty_master           /dev/ptm      128 0-1048575 pty:master=20
>   I am  using mknod command=20
> mknod /dev/ttyCPM0 c 204 46=20
>     ln -sf  console ttyCPM0=20
> mknod /dev/ttyCPM1 c 204 47
> mknod /dev/ttyCPM2 c 204 48
> mknod /dev/ttyCPM3 c 204 49 =20
>   even I am not able to open the device from the user space application
>   I want to write some data from the user space into the
> application
> But I am not able to open the device
>   please help me out
> regards
> Bharathi=20
>                                                                 =20
>  =20
> =20
>=20
> 	=09
> ---------------------------------
> =20
>  What are the most popular cars? Find out at Yahoo! Autos=20


--=20
Sincerely,=20
Vitaly

^ permalink raw reply

* RE: Yosemite/440EP why are readl()/ioread32() setuptoreadlittle-endian?
From: Jenkins, Clive @ 2006-02-02 11:26 UTC (permalink / raw)
  To: Eugene Surovegin; +Cc: linuxppc-embedded

I'm not sure all this fuss is justified in response to:

> What is the preferred way of accessing non-PCI devices then?
> Direct pointer access?
> Bye, Peter Korsgaard

Regardless of what standards or hardware might exist, I would be
happy if Linux provided alternatives to readl()... that converted
between big-endian and cpu-endian, so that I could write in my
driver, for example:

static inline my_readl(...)
{
#if (my interconnect is PCI or other little-endian)
    return(readl(...));
#else
    return(readl_be(...));
#endif
}

That must make my driver more portable in future circumstances.

Clive


-----Original Message-----
From: linuxppc-embedded-bounces@ozlabs.org
[mailto:linuxppc-embedded-bounces@ozlabs.org] On Behalf Of Eugene
Surovegin
Sent: 02 February 2006 10:44
To: Jenkins, Clive
Cc: linuxppc-embedded@ozlabs.org
Subject: Re: Yosemite/440EP why are readl()/ioread32()
setuptoreadlittle-endian?


On Thu, Feb 02, 2006 at 10:28:05AM -0000, Jenkins, Clive wrote:
> And what about direct connection to the local bus of the processor
chip?

What about it? It's _chip_ specific. And the way your "generic" stuff=20
will be connected to it will be chip or even design specific (yeah, hw=20
guys sometime wire it in some weird way). I fail to see how you can=20
have _generic_ I/O accessors for this case.

> =20
> > So basically, you have no _real_ life examples, so I'm wondering why

> > people need this "arch-independent" non-PCI I/O accessors for=20
> > something which doesn't exist.
>=20
> I could draft a design of such an example, and I could realise that
> design
> by building it. But I don't want to spend the time and money doing it.
> Neither do I want to spend time researching _real_ examples.
> It is much easier to allow for obvious possibilities that _could_
exist
> and probably will exist if they don't already, than searching the
world.

It's not as easy as you might think :). It must be=20
arch/bus/device/board specific in the general case.=20

You can try _specifying_ semantics for such generic accessors and=20
_then_ we can discuss this and I will very likely give you _real_=20
world examples when they will not work.

> Why be PCI-centric now, when we have experienced no end of problems
> because Linux was x86-centric in the past?

Well, until there is another _standard_ bus which is used on=20
different archs, having _generic_ cross-arch I/O accessors doesn't=20
make any sense.

I don't understand your point about not being PCI specific. It's of no=20
relevance what you or I think about PCI and x86. I have ported several=20
"standard" bus drivers to chip specific interconnects (MIPS and PPC)=20
and in every case code was bus or even board specific. I'm pretty much=20
aware about problems and solutions. But this is not what is being=20
discussed here. Until there is _standard_ for such interconnects (like=20
PCI) everything else is just wishful thinking.

--=20
Eugene

_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setup toreadlittle-endian?
From: Eugene Surovegin @ 2006-02-02 10:44 UTC (permalink / raw)
  To: Jenkins, Clive; +Cc: linuxppc-embedded
In-Reply-To: <35786B99AB3FDC45A8215724617919736D921D@gbrwgceumf01.eu.xerox.net>

On Thu, Feb 02, 2006 at 10:28:05AM -0000, Jenkins, Clive wrote:
> And what about direct connection to the local bus of the processor chip?

What about it? It's _chip_ specific. And the way your "generic" stuff 
will be connected to it will be chip or even design specific (yeah, hw 
guys sometime wire it in some weird way). I fail to see how you can 
have _generic_ I/O accessors for this case.

>  
> > So basically, you have no _real_ life examples, so I'm wondering why 
> > people need this "arch-independent" non-PCI I/O accessors for 
> > something which doesn't exist.
> 
> I could draft a design of such an example, and I could realise that
> design
> by building it. But I don't want to spend the time and money doing it.
> Neither do I want to spend time researching _real_ examples.
> It is much easier to allow for obvious possibilities that _could_ exist
> and probably will exist if they don't already, than searching the world.

It's not as easy as you might think :). It must be 
arch/bus/device/board specific in the general case. 

You can try _specifying_ semantics for such generic accessors and 
_then_ we can discuss this and I will very likely give you _real_ 
world examples when they will not work.

> Why be PCI-centric now, when we have experienced no end of problems
> because Linux was x86-centric in the past?

Well, until there is another _standard_ bus which is used on 
different archs, having _generic_ cross-arch I/O accessors doesn't 
make any sense.

I don't understand your point about not being PCI specific. It's of no 
relevance what you or I think about PCI and x86. I have ported several 
"standard" bus drivers to chip specific interconnects (MIPS and PPC) 
and in every case code was bus or even board specific. I'm pretty much 
aware about problems and solutions. But this is not what is being 
discussed here. Until there is _standard_ for such interconnects (like 
PCI) everything else is just wishful thinking.

-- 
Eugene

^ permalink raw reply

* RE: Yosemite/440EP why are readl()/ioread32() setup toreadlittle-endian?
From: Jenkins, Clive @ 2006-02-02 10:28 UTC (permalink / raw)
  To: Eugene Surovegin; +Cc: linuxppc-embedded

> > On Thu, Feb 02, 2006 at 09:35:56AM -0000, Jenkins, Clive wrote:
> > A driver for some device that could be connected to (or plugged
into)
> > a variety of different platforms of different architecture.
> > A driver for a core that could be implemented within an FPGA on
> > multiple platforms.

> Well, this is all nice but I was wondering about _real_ examples.
> When you are talking about "connecting" or "plugging" you have to keep

> in mind actual bus interconnect. So far AFAIK PCI (and derivatives)=20
> are the only cross-arch bus.

Yes, I do realise that in most cases PCI is used for cross-arch
interconnect. But without knowing about all the relevant hardware in the
world, I couldn't say that there are no other cross-arch buses.
And what about direct connection to the local bus of the processor chip?
=20
> So basically, you have no _real_ life examples, so I'm wondering why=20
> people need this "arch-independent" non-PCI I/O accessors for=20
> something which doesn't exist.

I could draft a design of such an example, and I could realise that
design
by building it. But I don't want to spend the time and money doing it.
Neither do I want to spend time researching _real_ examples.
It is much easier to allow for obvious possibilities that _could_ exist
and probably will exist if they don't already, than searching the world.

Why be PCI-centric now, when we have experienced no end of problems
because Linux was x86-centric in the past?

> I think the reason why Linux doesn't have this stuff follows from the=20
> previous paragraph.

Clive

^ permalink raw reply

* Re: [CFT] Don't use ASYNC_* nor SERIAL_IO_* with serial_core
From: Russell King @ 2006-02-02 10:27 UTC (permalink / raw)
  To: Linux Kernel List, linux-mips, linuxppc-dev, takata, pfg
In-Reply-To: <20060121211407.GA19984@dyn-67.arm.linux.org.uk>

Ping?

On Sat, Jan 21, 2006 at 09:14:07PM +0000, Russell King wrote:
> The serial_core layer has its own definitions for these, and I'd
> appreciate it if folk would use them instead of the old ASYNC_* and
> SERIAL_IO_* definitions.
> 
> They're compatible _at the moment_ but I make no guarantees that they
> will stay that way.  Hence, it's in your interest to ensure that you're
> using the correct definitions.
> 
> MIPS, PPC seem to be the architectures which are stuck in the past on
> this issue, as is the M32R SIO driver.
> 
> The ioc4_serial driver is worse.  It assumes that it can set/clear
> ASYNC_CTS_FLOW in the uart_info flags field, which is private to
> serial_core.  It also seems to set TTY_IO_ERROR followed by immediately
> clearing it (pointless), and then it writes to tty->alt_speed... which
> isn't used by the serial layer so is also pointless.
> 
> So, here's a patch to fix some of this crap up.  Please test and
> enjoy - I certainly didn't.
> 
>  arch/mips/cobalt/setup.c                   |    2 +-
>  arch/mips/lasat/setup.c                    |    4 ++--
>  arch/mips/mips-boards/atlas/atlas_setup.c  |    4 ++--
>  arch/mips/mips-boards/sead/sead_setup.c    |    4 ++--
>  arch/mips/mips-boards/sim/sim_setup.c      |    4 ++--
>  arch/mips/momentum/jaguar_atx/ja-console.c |    2 +-
>  arch/mips/pmc-sierra/yosemite/setup.c      |    2 +-
>  arch/mips/sgi-ip32/ip32-setup.c            |   13 ++++---------
>  arch/ppc/platforms/4xx/bamboo.c            |    4 ++--
>  arch/ppc/platforms/4xx/bubinga.c           |    4 ++--
>  arch/ppc/platforms/4xx/ebony.c             |    4 ++--
>  arch/ppc/platforms/4xx/luan.c              |    4 ++--
>  arch/ppc/platforms/4xx/ocotea.c            |    4 ++--
>  arch/ppc/platforms/4xx/xilinx_ml300.c      |    4 ++--
>  arch/ppc/platforms/4xx/yucca.c             |    4 ++--
>  arch/ppc/platforms/spruce.c                |    4 ++--
>  drivers/serial/ioc4_serial.c               |   14 --------------
>  drivers/serial/m32r_sio.c                  |    2 +-
>  18 files changed, 32 insertions(+), 51 deletions(-)
> 
> diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
> --- a/arch/mips/cobalt/setup.c
> +++ b/arch/mips/cobalt/setup.c
> @@ -139,7 +139,7 @@ void __init plat_setup(void)
>  		uart.type	= PORT_UNKNOWN;
>  		uart.uartclk	= 18432000;
>  		uart.irq	= COBALT_SERIAL_IRQ;
> -		uart.flags	= STD_COM_FLAGS;
> +		uart.flags	= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  		uart.iobase	= 0xc800000;
>  		uart.iotype	= UPIO_PORT;
>  
> diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
> --- a/arch/mips/lasat/setup.c
> +++ b/arch/mips/lasat/setup.c
> @@ -134,8 +134,8 @@ void __init serial_init(void)
>  
>  	memset(&s, 0, sizeof(s));
>  
> -	s.flags = STD_COM_FLAGS;
> -	s.iotype = SERIAL_IO_MEM;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
> +	s.iotype = UPIO_MEM;
>  
>  	if (mips_machtype == MACH_LASAT_100) {
>  		s.uartclk = LASAT_BASE_BAUD_100 * 16;
> diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
> --- a/arch/mips/mips-boards/atlas/atlas_setup.c
> +++ b/arch/mips/mips-boards/atlas/atlas_setup.c
> @@ -82,8 +82,8 @@ static void __init serial_init(void)
>  #endif
>  	s.irq = ATLASINT_UART;
>  	s.uartclk = ATLAS_BASE_BAUD * 16;
> -	s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
> -	s.iotype = SERIAL_IO_PORT;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ;
> +	s.iotype = UPIO_PORT;
>  	s.regshift = 3;
>  
>  	if (early_serial_setup(&s) != 0) {
> diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c
> --- a/arch/mips/mips-boards/sead/sead_setup.c
> +++ b/arch/mips/mips-boards/sead/sead_setup.c
> @@ -71,8 +71,8 @@ static void __init serial_init(void)
>  #endif
>  	s.irq = MIPSCPU_INT_BASE + MIPSCPU_INT_UART0;
>  	s.uartclk = SEAD_BASE_BAUD * 16;
> -	s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
> -	s.iotype = 0;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ;
> +	s.iotype = UPIO_PORT;
>  	s.regshift = 3;
>  
>  	if (early_serial_setup(&s) != 0) {
> diff --git a/arch/mips/mips-boards/sim/sim_setup.c b/arch/mips/mips-boards/sim/sim_setup.c
> --- a/arch/mips/mips-boards/sim/sim_setup.c
> +++ b/arch/mips/mips-boards/sim/sim_setup.c
> @@ -88,8 +88,8 @@ static void __init serial_init(void)
>  	 but poll for now */
>  	s.irq =  0;
>  	s.uartclk = BASE_BAUD * 16;
> -	s.flags = ASYNC_BOOT_AUTOCONF | UPF_SKIP_TEST;
> -	s.iotype = SERIAL_IO_PORT | ASYNC_SKIP_TEST;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
> +	s.iotype = UPIO_PORT;
>  	s.regshift = 0;
>  	s.timeout = 4;
>  
> diff --git a/arch/mips/momentum/jaguar_atx/ja-console.c b/arch/mips/momentum/jaguar_atx/ja-console.c
> --- a/arch/mips/momentum/jaguar_atx/ja-console.c
> +++ b/arch/mips/momentum/jaguar_atx/ja-console.c
> @@ -93,7 +93,7 @@ static void inline ja_console_probe(void
>  	up.uartclk	= JAGUAR_ATX_UART_CLK;
>  	up.regshift	= 2;
>  	up.iotype	= UPIO_MEM;
> -	up.flags	= ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	up.flags	= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	up.line		= 0;
>  
>  	if (early_serial_setup(&up))
> diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
> --- a/arch/mips/pmc-sierra/yosemite/setup.c
> +++ b/arch/mips/pmc-sierra/yosemite/setup.c
> @@ -185,7 +185,7 @@ static void __init py_uart_setup(void)
>  	up.uartclk      = TITAN_UART_CLK;
>  	up.regshift     = 0;
>  	up.iotype       = UPIO_MEM;
> -	up.flags        = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	up.flags        = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	up.line         = 0;
>  
>  	if (early_serial_setup(&up))
> diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
> --- a/arch/mips/sgi-ip32/ip32-setup.c
> +++ b/arch/mips/sgi-ip32/ip32-setup.c
> @@ -66,11 +66,6 @@ static inline void str2eaddr(unsigned ch
>  #include <linux/tty.h>
>  #include <linux/serial.h>
>  #include <linux/serial_core.h>
> -extern int early_serial_setup(struct uart_port *port);
> -
> -#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
> -#define BASE_BAUD (1843200 / 16)
> -
>  #endif /* CONFIG_SERIAL_8250 */
>  
>  /* An arbitrary time; this can be decreased if reliability looks good */
> @@ -110,8 +105,8 @@ void __init plat_setup(void)
>  		o2_serial[0].type	= PORT_16550A;
>  		o2_serial[0].line	= 0;
>  		o2_serial[0].irq	= MACEISA_SERIAL1_IRQ;
> -		o2_serial[0].flags	= STD_COM_FLAGS;
> -		o2_serial[0].uartclk	= BASE_BAUD * 16;
> +		o2_serial[0].flags	= UPF_SKIP_TEST;
> +		o2_serial[0].uartclk	= 1843200;
>  		o2_serial[0].iotype	= UPIO_MEM;
>  		o2_serial[0].membase	= (char *)&mace->isa.serial1;
>  		o2_serial[0].fifosize	= 14;
> @@ -121,8 +116,8 @@ void __init plat_setup(void)
>  		o2_serial[1].type	= PORT_16550A;
>  		o2_serial[1].line	= 1;
>  		o2_serial[1].irq	= MACEISA_SERIAL2_IRQ;
> -		o2_serial[1].flags	= STD_COM_FLAGS;
> -		o2_serial[1].uartclk	= BASE_BAUD * 16;
> +		o2_serial[1].flags	= UPF_SKIP_TEST;
> +		o2_serial[1].uartclk	= 1843200;
>  		o2_serial[1].iotype	= UPIO_MEM;
>  		o2_serial[1].membase	= (char *)&mace->isa.serial2;
>  		o2_serial[1].fifosize	= 14;
> diff --git a/arch/ppc/platforms/4xx/bamboo.c b/arch/ppc/platforms/4xx/bamboo.c
> --- a/arch/ppc/platforms/4xx/bamboo.c
> +++ b/arch/ppc/platforms/4xx/bamboo.c
> @@ -332,8 +332,8 @@ bamboo_early_serial_map(void)
>  	port.irq = 0;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c
> --- a/arch/ppc/platforms/4xx/bubinga.c
> +++ b/arch/ppc/platforms/4xx/bubinga.c
> @@ -97,8 +97,8 @@ bubinga_early_serial_map(void)
>  	port.irq = ACTING_UART0_INT;
>  	port.uartclk = uart_clock;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c
> --- a/arch/ppc/platforms/4xx/ebony.c
> +++ b/arch/ppc/platforms/4xx/ebony.c
> @@ -225,8 +225,8 @@ ebony_early_serial_map(void)
>  	port.irq = 0;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c
> --- a/arch/ppc/platforms/4xx/luan.c
> +++ b/arch/ppc/platforms/4xx/luan.c
> @@ -279,8 +279,8 @@ luan_early_serial_map(void)
>  	port.irq = UART0_INT;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
> --- a/arch/ppc/platforms/4xx/ocotea.c
> +++ b/arch/ppc/platforms/4xx/ocotea.c
> @@ -248,8 +248,8 @@ ocotea_early_serial_map(void)
>  	port.irq = UART0_INT;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
> --- a/arch/ppc/platforms/4xx/xilinx_ml300.c
> +++ b/arch/ppc/platforms/4xx/xilinx_ml300.c
> @@ -95,8 +95,8 @@ ml300_early_serial_map(void)
>  		port.irq = old_ports[i].irq;
>  		port.uartclk = old_ports[i].baud_base * 16;
>  		port.regshift = old_ports[i].iomem_reg_shift;
> -		port.iotype = SERIAL_IO_MEM;
> -		port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +		port.iotype = UPIO_MEM;
> +		port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  		port.line = i;
>  
>  		if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/yucca.c b/arch/ppc/platforms/4xx/yucca.c
> --- a/arch/ppc/platforms/4xx/yucca.c
> +++ b/arch/ppc/platforms/4xx/yucca.c
> @@ -305,8 +305,8 @@ yucca_early_serial_map(void)
>  	port.irq = UART0_INT;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c
> --- a/arch/ppc/platforms/spruce.c
> +++ b/arch/ppc/platforms/spruce.c
> @@ -176,8 +176,8 @@ spruce_early_serial_map(void)
>  	memset(&serial_req, 0, sizeof(serial_req));
>  	serial_req.uartclk = uart_clk;
>  	serial_req.irq = UART0_INT;
> -	serial_req.flags = ASYNC_BOOT_AUTOCONF;
> -	serial_req.iotype = SERIAL_IO_MEM;
> +	serial_req.flags = UPF_BOOT_AUTOCONF;
> +	serial_req.iotype = UPIO_MEM;
>  	serial_req.membase = (u_char *)UART0_IO_BASE;
>  	serial_req.regshift = 0;
>  
> diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
> --- a/drivers/serial/ioc4_serial.c
> +++ b/drivers/serial/ioc4_serial.c
> @@ -1717,11 +1717,9 @@ ioc4_change_speed(struct uart_port *the_
>  	}
>  
>  	if (cflag & CRTSCTS) {
> -		info->flags |= ASYNC_CTS_FLOW;
>  		port->ip_sscr |= IOC4_SSCR_HFC_EN;
>  	}
>  	else {
> -		info->flags &= ~ASYNC_CTS_FLOW;
>  		port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
>  	}
>  	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
> @@ -1760,18 +1758,6 @@ static inline int ic4_startup_local(stru
>  
>  	info = the_port->info;
>  
> -	if (info->tty) {
> -		set_bit(TTY_IO_ERROR, &info->tty->flags);
> -		clear_bit(TTY_IO_ERROR, &info->tty->flags);
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
> -			info->tty->alt_speed = 57600;
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
> -			info->tty->alt_speed = 115200;
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
> -			info->tty->alt_speed = 230400;
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
> -			info->tty->alt_speed = 460800;
> -	}
>  	local_open(port);
>  
>  	/* set the speed of the serial port */
> diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
> --- a/drivers/serial/m32r_sio.c
> +++ b/drivers/serial/m32r_sio.c
> @@ -80,7 +80,7 @@
>  #include <asm/serial.h>
>  
>  /* Standard COM flags */
> -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
> +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
>  
>  /*
>   * SERIAL_PORT_DFNS tells us about built-in ports that have no

> diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
> --- a/arch/mips/cobalt/setup.c
> +++ b/arch/mips/cobalt/setup.c
> @@ -139,7 +139,7 @@ void __init plat_setup(void)
>  		uart.type	= PORT_UNKNOWN;
>  		uart.uartclk	= 18432000;
>  		uart.irq	= COBALT_SERIAL_IRQ;
> -		uart.flags	= STD_COM_FLAGS;
> +		uart.flags	= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  		uart.iobase	= 0xc800000;
>  		uart.iotype	= UPIO_PORT;
>  
> diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
> --- a/arch/mips/lasat/setup.c
> +++ b/arch/mips/lasat/setup.c
> @@ -134,8 +134,8 @@ void __init serial_init(void)
>  
>  	memset(&s, 0, sizeof(s));
>  
> -	s.flags = STD_COM_FLAGS;
> -	s.iotype = SERIAL_IO_MEM;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
> +	s.iotype = UPIO_MEM;
>  
>  	if (mips_machtype == MACH_LASAT_100) {
>  		s.uartclk = LASAT_BASE_BAUD_100 * 16;
> diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
> --- a/arch/mips/mips-boards/atlas/atlas_setup.c
> +++ b/arch/mips/mips-boards/atlas/atlas_setup.c
> @@ -82,8 +82,8 @@ static void __init serial_init(void)
>  #endif
>  	s.irq = ATLASINT_UART;
>  	s.uartclk = ATLAS_BASE_BAUD * 16;
> -	s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
> -	s.iotype = SERIAL_IO_PORT;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ;
> +	s.iotype = UPIO_PORT;
>  	s.regshift = 3;
>  
>  	if (early_serial_setup(&s) != 0) {
> diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c
> --- a/arch/mips/mips-boards/sead/sead_setup.c
> +++ b/arch/mips/mips-boards/sead/sead_setup.c
> @@ -71,8 +71,8 @@ static void __init serial_init(void)
>  #endif
>  	s.irq = MIPSCPU_INT_BASE + MIPSCPU_INT_UART0;
>  	s.uartclk = SEAD_BASE_BAUD * 16;
> -	s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
> -	s.iotype = 0;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ;
> +	s.iotype = UPIO_PORT;
>  	s.regshift = 3;
>  
>  	if (early_serial_setup(&s) != 0) {
> diff --git a/arch/mips/mips-boards/sim/sim_setup.c b/arch/mips/mips-boards/sim/sim_setup.c
> --- a/arch/mips/mips-boards/sim/sim_setup.c
> +++ b/arch/mips/mips-boards/sim/sim_setup.c
> @@ -88,8 +88,8 @@ static void __init serial_init(void)
>  	 but poll for now */
>  	s.irq =  0;
>  	s.uartclk = BASE_BAUD * 16;
> -	s.flags = ASYNC_BOOT_AUTOCONF | UPF_SKIP_TEST;
> -	s.iotype = SERIAL_IO_PORT | ASYNC_SKIP_TEST;
> +	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
> +	s.iotype = UPIO_PORT;
>  	s.regshift = 0;
>  	s.timeout = 4;
>  
> diff --git a/arch/mips/momentum/jaguar_atx/ja-console.c b/arch/mips/momentum/jaguar_atx/ja-console.c
> --- a/arch/mips/momentum/jaguar_atx/ja-console.c
> +++ b/arch/mips/momentum/jaguar_atx/ja-console.c
> @@ -93,7 +93,7 @@ static void inline ja_console_probe(void
>  	up.uartclk	= JAGUAR_ATX_UART_CLK;
>  	up.regshift	= 2;
>  	up.iotype	= UPIO_MEM;
> -	up.flags	= ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	up.flags	= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	up.line		= 0;
>  
>  	if (early_serial_setup(&up))
> diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
> --- a/arch/mips/pmc-sierra/yosemite/setup.c
> +++ b/arch/mips/pmc-sierra/yosemite/setup.c
> @@ -185,7 +185,7 @@ static void __init py_uart_setup(void)
>  	up.uartclk      = TITAN_UART_CLK;
>  	up.regshift     = 0;
>  	up.iotype       = UPIO_MEM;
> -	up.flags        = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	up.flags        = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	up.line         = 0;
>  
>  	if (early_serial_setup(&up))
> diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
> --- a/arch/mips/sgi-ip32/ip32-setup.c
> +++ b/arch/mips/sgi-ip32/ip32-setup.c
> @@ -66,11 +66,6 @@ static inline void str2eaddr(unsigned ch
>  #include <linux/tty.h>
>  #include <linux/serial.h>
>  #include <linux/serial_core.h>
> -extern int early_serial_setup(struct uart_port *port);
> -
> -#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
> -#define BASE_BAUD (1843200 / 16)
> -
>  #endif /* CONFIG_SERIAL_8250 */
>  
>  /* An arbitrary time; this can be decreased if reliability looks good */
> @@ -110,8 +105,8 @@ void __init plat_setup(void)
>  		o2_serial[0].type	= PORT_16550A;
>  		o2_serial[0].line	= 0;
>  		o2_serial[0].irq	= MACEISA_SERIAL1_IRQ;
> -		o2_serial[0].flags	= STD_COM_FLAGS;
> -		o2_serial[0].uartclk	= BASE_BAUD * 16;
> +		o2_serial[0].flags	= UPF_SKIP_TEST;
> +		o2_serial[0].uartclk	= 1843200;
>  		o2_serial[0].iotype	= UPIO_MEM;
>  		o2_serial[0].membase	= (char *)&mace->isa.serial1;
>  		o2_serial[0].fifosize	= 14;
> @@ -121,8 +116,8 @@ void __init plat_setup(void)
>  		o2_serial[1].type	= PORT_16550A;
>  		o2_serial[1].line	= 1;
>  		o2_serial[1].irq	= MACEISA_SERIAL2_IRQ;
> -		o2_serial[1].flags	= STD_COM_FLAGS;
> -		o2_serial[1].uartclk	= BASE_BAUD * 16;
> +		o2_serial[1].flags	= UPF_SKIP_TEST;
> +		o2_serial[1].uartclk	= 1843200;
>  		o2_serial[1].iotype	= UPIO_MEM;
>  		o2_serial[1].membase	= (char *)&mace->isa.serial2;
>  		o2_serial[1].fifosize	= 14;
> diff --git a/arch/ppc/platforms/4xx/bamboo.c b/arch/ppc/platforms/4xx/bamboo.c
> --- a/arch/ppc/platforms/4xx/bamboo.c
> +++ b/arch/ppc/platforms/4xx/bamboo.c
> @@ -332,8 +332,8 @@ bamboo_early_serial_map(void)
>  	port.irq = 0;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c
> --- a/arch/ppc/platforms/4xx/bubinga.c
> +++ b/arch/ppc/platforms/4xx/bubinga.c
> @@ -97,8 +97,8 @@ bubinga_early_serial_map(void)
>  	port.irq = ACTING_UART0_INT;
>  	port.uartclk = uart_clock;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c
> --- a/arch/ppc/platforms/4xx/ebony.c
> +++ b/arch/ppc/platforms/4xx/ebony.c
> @@ -225,8 +225,8 @@ ebony_early_serial_map(void)
>  	port.irq = 0;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c
> --- a/arch/ppc/platforms/4xx/luan.c
> +++ b/arch/ppc/platforms/4xx/luan.c
> @@ -279,8 +279,8 @@ luan_early_serial_map(void)
>  	port.irq = UART0_INT;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
> --- a/arch/ppc/platforms/4xx/ocotea.c
> +++ b/arch/ppc/platforms/4xx/ocotea.c
> @@ -248,8 +248,8 @@ ocotea_early_serial_map(void)
>  	port.irq = UART0_INT;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
> --- a/arch/ppc/platforms/4xx/xilinx_ml300.c
> +++ b/arch/ppc/platforms/4xx/xilinx_ml300.c
> @@ -95,8 +95,8 @@ ml300_early_serial_map(void)
>  		port.irq = old_ports[i].irq;
>  		port.uartclk = old_ports[i].baud_base * 16;
>  		port.regshift = old_ports[i].iomem_reg_shift;
> -		port.iotype = SERIAL_IO_MEM;
> -		port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +		port.iotype = UPIO_MEM;
> +		port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  		port.line = i;
>  
>  		if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/4xx/yucca.c b/arch/ppc/platforms/4xx/yucca.c
> --- a/arch/ppc/platforms/4xx/yucca.c
> +++ b/arch/ppc/platforms/4xx/yucca.c
> @@ -305,8 +305,8 @@ yucca_early_serial_map(void)
>  	port.irq = UART0_INT;
>  	port.uartclk = clocks.uart0;
>  	port.regshift = 0;
> -	port.iotype = SERIAL_IO_MEM;
> -	port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
> +	port.iotype = UPIO_MEM;
> +	port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
>  	port.line = 0;
>  
>  	if (early_serial_setup(&port) != 0) {
> diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c
> --- a/arch/ppc/platforms/spruce.c
> +++ b/arch/ppc/platforms/spruce.c
> @@ -176,8 +176,8 @@ spruce_early_serial_map(void)
>  	memset(&serial_req, 0, sizeof(serial_req));
>  	serial_req.uartclk = uart_clk;
>  	serial_req.irq = UART0_INT;
> -	serial_req.flags = ASYNC_BOOT_AUTOCONF;
> -	serial_req.iotype = SERIAL_IO_MEM;
> +	serial_req.flags = UPF_BOOT_AUTOCONF;
> +	serial_req.iotype = UPIO_MEM;
>  	serial_req.membase = (u_char *)UART0_IO_BASE;
>  	serial_req.regshift = 0;
>  
> diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
> --- a/drivers/serial/ioc4_serial.c
> +++ b/drivers/serial/ioc4_serial.c
> @@ -1717,11 +1717,9 @@ ioc4_change_speed(struct uart_port *the_
>  	}
>  
>  	if (cflag & CRTSCTS) {
> -		info->flags |= ASYNC_CTS_FLOW;
>  		port->ip_sscr |= IOC4_SSCR_HFC_EN;
>  	}
>  	else {
> -		info->flags &= ~ASYNC_CTS_FLOW;
>  		port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
>  	}
>  	writel(port->ip_sscr, &port->ip_serial_regs->sscr);
> @@ -1760,18 +1758,6 @@ static inline int ic4_startup_local(stru
>  
>  	info = the_port->info;
>  
> -	if (info->tty) {
> -		set_bit(TTY_IO_ERROR, &info->tty->flags);
> -		clear_bit(TTY_IO_ERROR, &info->tty->flags);
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
> -			info->tty->alt_speed = 57600;
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
> -			info->tty->alt_speed = 115200;
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
> -			info->tty->alt_speed = 230400;
> -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
> -			info->tty->alt_speed = 460800;
> -	}
>  	local_open(port);
>  
>  	/* set the speed of the serial port */
> diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
> --- a/drivers/serial/m32r_sio.c
> +++ b/drivers/serial/m32r_sio.c
> @@ -80,7 +80,7 @@
>  #include <asm/serial.h>
>  
>  /* Standard COM flags */
> -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
> +#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
>  
>  /*
>   * SERIAL_PORT_DFNS tells us about built-in ports that have no


-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

^ permalink raw reply

* Re: Yosemite/440EP why are readl()/ioread32() setup to readlittle-endian?
From: Eugene Surovegin @ 2006-02-02  9:46 UTC (permalink / raw)
  To: Jenkins, Clive; +Cc: linuxppc-embedded
In-Reply-To: <35786B99AB3FDC45A8215724617919736D921C@gbrwgceumf01.eu.xerox.net>

On Thu, Feb 02, 2006 at 09:35:56AM -0000, Jenkins, Clive wrote:
> A driver for some device that could be connected to (or plugged into)
> a variety of different platforms of different architecture.
> A driver for a core that could be implemented within an FPGA on
> multiple platforms.

Well, this is all nice but I was wondering about _real_ examples.
When you are talking about "connecting" or "plugging" you have to keep 
in mind actual bus interconnect. So far AFAIK PCI (and derivatives) 
are the only cross-arch bus.

So basically, you have no _real_ life examples, so I'm wondering why 
people need this "arch-independent" non-PCI I/O accessors for 
something which doesn't exist.

I think the reason why Linux doesn't have this stuff follows from the 
previous paragraph.

-- 
Eugene

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox