LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* 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: 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

* 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() 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: 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

* [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

* [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

* 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

* 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: [PATCH] Add fec support for mpc52xx
From: Dale Farnsworth @ 2006-02-02 19:37 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: Sylvain Munaut, John Rigby
In-Reply-To: <43E24DA6.9@freescale.com>

In article <43E24DA6.9@freescale.com> John Rigby wrote:
> Adds fec support, requires bestcom patch.  Applies to Sylvains git tree.

Hmm, I thought that fec support was already in Sylvain's git tree.

I'm sure Sylvain intended it to be there.

>From http://ozlabs.org/pipermail/linuxppc-embedded/2005-June/018887.html:
> Date: Sun, 19 Jun 2005 00:15:32 +0200
> From: Sylvain Munaut <tnt@246tNt.com>
> 
> Following the obvious demand for it :
> 
> rsync://gitbits.246tNt.com/gitbits/linux-2.6-mpc52xx.git
> http://gitbits.246tNt.com/gitweb.cgi?p=linux-2.6-mpc52xx.git;a=summary
> 
> Hopefully the server is setup correctly ...
> It's not _heavily_ tested but it seems to works fine in the few test I
> made.
> 
> What in there :
>  - I2C patches that are already sent upstream but not yet in Linus tree
>  - Change of the mpc52xx uart device name and device ids to a range in
>    the low density serial port major. Also it's now named ttyPSC? so
>    you need to update you kernel command line (else you won't see any
>    console). Note that the ids and names choosed are NOT YET OFFICIAL,
>    I just included it in this release because some people were seeing
>    conflict with the other ids. So the name and ids may change ...
>  - Some other patches that will soon be sent upstream, just waiting
>    for you to test see if it has any negative impact.
>  - FEC and BestComm rewrite from Dale, with some improvement. For eg,
>    the FEC task now handle misaligment so the manual alignment code
>    has been removed, ...

I hope Sylvain can resurrect the 2.6 FEC code that he, I and others
worked on.

-Dale

^ permalink raw reply

* Re: [PATCH] Add fec support for mpc52xx
From: John Rigby @ 2006-02-02 19:54 UTC (permalink / raw)
  To: Dale Farnsworth; +Cc: Linuxppc-embedded
In-Reply-To: <20060202193734.22145.qmail@farnsworth.org>

Sylvain has not added bestcomm/fec to his latest tree yet:

http://gitbits.246tNt.com/gitbits/linux-2.6-mpc52xx

you need to apply this patch:

http://gitbits.246tNt.com/patches/bcomm-to-split.diff

The patches I sent to the list are just newer bestcomm code from
freescale and an fec driver that works with it.  I don't make
any claims about it being better just newer and different.

 (I haven't cleanly splitted it up yet and right now I must go, so it's
probably gonna be in the git tree this week, under the 'bestcomm' head ;)



On 2 Feb 2006 19:37:34 -0000, Dale Farnsworth <dale@farnsworth.org> wrote:
> In article <43E24DA6.9@freescale.com> John Rigby wrote:
> > Adds fec support, requires bestcom patch.  Applies to Sylvains git tree=
.
>
> Hmm, I thought that fec support was already in Sylvain's git tree.
>
> I'm sure Sylvain intended it to be there.
>
> From http://ozlabs.org/pipermail/linuxppc-embedded/2005-June/018887.html:
> > Date: Sun, 19 Jun 2005 00:15:32 +0200
> > From: Sylvain Munaut <tnt@246tNt.com>
> >
> > Following the obvious demand for it :
> >
> > rsync://gitbits.246tNt.com/gitbits/linux-2.6-mpc52xx.git
> > http://gitbits.246tNt.com/gitweb.cgi?p=3Dlinux-2.6-mpc52xx.git;a=3Dsumm=
ary
> >
> > Hopefully the server is setup correctly ...
> > It's not _heavily_ tested but it seems to works fine in the few test I
> > made.
> >
> > What in there :
> >  - I2C patches that are already sent upstream but not yet in Linus tree
> >  - Change of the mpc52xx uart device name and device ids to a range in
> >    the low density serial port major. Also it's now named ttyPSC? so
> >    you need to update you kernel command line (else you won't see any
> >    console). Note that the ids and names choosed are NOT YET OFFICIAL,
> >    I just included it in this release because some people were seeing
> >    conflict with the other ids. So the name and ids may change ...
> >  - Some other patches that will soon be sent upstream, just waiting
> >    for you to test see if it has any negative impact.
> >  - FEC and BestComm rewrite from Dale, with some improvement. For eg,
> >    the FEC task now handle misaligment so the manual alignment code
> >    has been removed, ...
>
> I hope Sylvain can resurrect the 2.6 FEC code that he, I and others
> worked on.
>
> -Dale
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>

^ permalink raw reply

* [PATCH] powerpc: Cleanup MPC83xx platform support
From: Kumar Gala @ 2006-02-02 19:50 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Moved some code around so its usable by more systems than just
the MPC834x SYS.

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

---
commit 3a37a9fa1aa28844651449eda0c31485ad202b01
tree 30998d96fa22fbab7517be304fc004ba02377181
parent 7ddda6a6630d95f800fbf848b00bd1d685c9bba4
author Kumar Gala <galak@kernel.crashing.org> Thu, 02 Feb 2006 13:16:20 -0600
committer Kumar Gala <galak@kernel.crashing.org> Thu, 02 Feb 2006 13:16:20 -0600

 arch/powerpc/platforms/83xx/Makefile      |    4 ++
 arch/powerpc/platforms/83xx/misc.c        |   55 ++++++++++++++++++++++++++++
 arch/powerpc/platforms/83xx/mpc834x_sys.c |   58 -----------------------------
 arch/powerpc/platforms/83xx/mpc83xx.h     |    3 ++
 arch/powerpc/platforms/83xx/pci.c         |   13 +++++--
 5 files changed, 71 insertions(+), 62 deletions(-)

diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 9d8b28e..5c72367 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -1,4 +1,6 @@
 #
 # Makefile for the PowerPC 83xx linux kernel.
 #
-obj-$(CONFIG_MPC834x_SYS)	+= mpc834x_sys.o pci.o
+obj-y				:= misc.o
+obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_MPC834x_SYS)	+= mpc834x_sys.o
diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c
new file mode 100644
index 0000000..0eb3d99
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/misc.c
@@ -0,0 +1,55 @@
+/*
+ * misc setup functions for MPC83xx
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc83xx.h"
+
+void mpc83xx_restart(char *cmd)
+{
+#define RST_OFFSET	0x00000900
+#define RST_PROT_REG	0x00000018
+#define RST_CTRL_REG	0x0000001c
+	__be32 __iomem *reg;
+
+	/* map reset register space */
+	reg = ioremap(get_immrbase() + 0x900, 0xff);
+
+	local_irq_disable();
+
+	/* enable software reset "RSTE" */
+	out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
+
+	/* set software hard reset */
+	out_be32(reg + (RST_CTRL_REG >> 2), 0x52535445);
+	for (;;) ;
+}
+
+long __init mpc83xx_time_init(void)
+{
+#define SPCR_OFFSET	0x00000110
+#define SPCR_TBEN	0x00400000
+	__be32 __iomem *spcr = ioremap(get_immrbase() + SPCR_OFFSET, 4);
+	__be32 tmp;
+
+	tmp = in_be32(spcr);
+	out_be32(spcr, tmp | SPCR_TBEN);
+
+	iounmap(spcr);
+
+	return 0;
+}
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
index 2098dd0..7d5a278 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_sys.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c
@@ -24,22 +24,15 @@
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
-#include <linux/module.h>
-#include <linux/fsl_devices.h>
 
 #include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
 #include <asm/atomic.h>
 #include <asm/time.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/ipic.h>
 #include <asm/bootinfo.h>
-#include <asm/pci-bridge.h>
-#include <asm/mpc83xx.h>
 #include <asm/irq.h>
-#include <mm/mmu_decl.h>
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <sysdev/fsl_soc.h>
@@ -52,8 +45,6 @@ unsigned long isa_mem_base = 0;
 #endif
 
 #ifdef CONFIG_PCI
-extern int mpc83xx_pci2_busno;
-
 static int
 mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
 {
@@ -78,17 +69,6 @@ mpc83xx_map_irq(struct pci_dev *dev, uns
 	const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
 	return PCI_IRQ_TABLE_LOOKUP;
 }
-
-static int
-mpc83xx_exclude_device(u_char bus, u_char devfn)
-{
-	if (bus == 0 && PCI_SLOT(devfn) == 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (mpc83xx_pci2_busno)
-		if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
-			return PCIBIOS_DEVICE_NOT_FOUND;
-	return PCIBIOS_SUCCESSFUL;
-}
 #endif /* CONFIG_PCI */
 
 /* ************************************************************************
@@ -180,42 +160,6 @@ mpc834x_rtc_hookup(void)
 late_initcall(mpc834x_rtc_hookup);
 #endif
 
-static void
-mpc83xx_restart(char *cmd)
-{
-#define RST_OFFSET	0x00000900
-#define RST_PROT_REG	0x00000018
-#define RST_CTRL_REG	0x0000001c
-	__be32 __iomem *reg;
-
-	// map reset register space
-	reg = ioremap(get_immrbase() + 0x900, 0xff);
-
-	local_irq_disable();
-
-	/* enable software reset "RSTE" */
-	out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
-
-	/* set software hard reset */
-	out_be32(reg + (RST_CTRL_REG >> 2), 0x52535445);
-	for(;;);
-}
-
-static long __init
-mpc83xx_time_init(void)
-{
-#define SPCR_OFFSET	0x00000110
-#define SPCR_TBEN	0x00400000
-	__be32 __iomem *spcr = ioremap(get_immrbase() + SPCR_OFFSET, 4);
-	__be32 tmp;
-
-	tmp = in_be32(spcr);
-	out_be32(spcr, tmp|SPCR_TBEN);
-
-	iounmap(spcr);
-
-	return 0;
-}
 void __init
 platform_init(void)
 {
@@ -239,5 +183,3 @@ platform_init(void)
 
 	return;
 }
-
-
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
index ce9e66a..228d5c4 100644
--- a/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -10,5 +10,8 @@
  */
 
 extern int add_bridge(struct device_node *dev);
+extern int mpc83xx_exclude_device(u_char bus, u_char devfn);
+extern void mpc83xx_restart(char *cmd);
+extern long mpc83xx_time_init(void);
 
 #endif /* __MPC83XX_H__ */
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 469cdac..70e28fc 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -36,7 +36,16 @@
 
 int mpc83xx_pci2_busno;
 
-#ifdef CONFIG_PCI
+int mpc83xx_exclude_device(u_char bus, u_char devfn)
+{
+	if (bus == 0 && PCI_SLOT(devfn) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (mpc83xx_pci2_busno)
+		if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	return PCIBIOS_SUCCESSFUL;
+}
+
 int __init add_bridge(struct device_node *dev)
 {
 	int len;
@@ -95,5 +104,3 @@ int __init add_bridge(struct device_node
 
 	return 0;
 }
-
-#endif

^ permalink raw reply related

* [PATCH] powerpc: Lindent platforms/83xx
From: Kumar Gala @ 2006-02-02 19:51 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Ran arch/powerpc/platforms/83xx through Lindent

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

---
commit 07128b4c47be22093a6c4a1972bae78994e2d11c
tree 0f81fd48006d8b92598cd23d89ab07910756711a
parent 3a37a9fa1aa28844651449eda0c31485ad202b01
author Kumar Gala <galak@kernel.crashing.org> Thu, 02 Feb 2006 13:48:35 -0600
committer Kumar Gala <galak@kernel.crashing.org> Thu, 02 Feb 2006 13:48:35 -0600

 arch/powerpc/platforms/83xx/mpc834x_sys.c |   31 +++++++++++++----------------
 arch/powerpc/platforms/83xx/mpc834x_sys.h |    2 +-
 arch/powerpc/platforms/83xx/mpc83xx.h     |    2 +-
 arch/powerpc/platforms/83xx/pci.c         |    8 ++++---
 4 files changed, 20 insertions(+), 23 deletions(-)

diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
index 7d5a278..7c18b4c 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_sys.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c
@@ -69,15 +69,14 @@ mpc83xx_map_irq(struct pci_dev *dev, uns
 	const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
 	return PCI_IRQ_TABLE_LOOKUP;
 }
-#endif /* CONFIG_PCI */
+#endif				/* CONFIG_PCI */
 
 /* ************************************************************************
  *
  * Setup the architecture
  *
  */
-static void __init
-mpc834x_sys_setup_arch(void)
+static void __init mpc834x_sys_setup_arch(void)
 {
 	struct device_node *np;
 
@@ -86,14 +85,14 @@ mpc834x_sys_setup_arch(void)
 
 	np = of_find_node_by_type(NULL, "cpu");
 	if (np != 0) {
-		unsigned int *fp = (int *) get_property(np, "clock-frequency", NULL);
+		unsigned int *fp =
+		    (int *)get_property(np, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
 			loops_per_jiffy = 50000000 / HZ;
 		of_node_put(np);
 	}
-
 #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		add_bridge(np);
@@ -104,14 +103,13 @@ mpc834x_sys_setup_arch(void)
 #endif
 
 #ifdef  CONFIG_ROOT_NFS
-		ROOT_DEV = Root_NFS;
+	ROOT_DEV = Root_NFS;
 #else
-		ROOT_DEV = Root_HDA1;
+	ROOT_DEV = Root_HDA1;
 #endif
 }
 
-void __init
-mpc834x_sys_init_IRQ(void)
+void __init mpc834x_sys_init_IRQ(void)
 {
 	u8 senses[8] = {
 		0,			/* EXT 0 */
@@ -140,28 +138,27 @@ mpc834x_sys_init_IRQ(void)
 }
 
 #if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
-extern ulong	ds1374_get_rtc_time(void);
-extern int	ds1374_set_rtc_time(ulong);
+extern ulong ds1374_get_rtc_time(void);
+extern int ds1374_set_rtc_time(ulong);
 
-static int __init
-mpc834x_rtc_hookup(void)
+static int __init mpc834x_rtc_hookup(void)
 {
-	struct timespec	tv;
+	struct timespec tv;
 
 	ppc_md.get_rtc_time = ds1374_get_rtc_time;
 	ppc_md.set_rtc_time = ds1374_set_rtc_time;
 
 	tv.tv_nsec = 0;
-	tv.tv_sec = (ppc_md.get_rtc_time)();
+	tv.tv_sec = (ppc_md.get_rtc_time) ();
 	do_settimeofday(&tv);
 
 	return 0;
 }
+
 late_initcall(mpc834x_rtc_hookup);
 #endif
 
-void __init
-platform_init(void)
+void __init platform_init(void)
 {
 	/* setup the PowerPC module struct */
 	ppc_md.setup_arch = mpc834x_sys_setup_arch;
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h
index e4ca39f..fedecb7 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_sys.h
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.h
@@ -20,4 +20,4 @@
 #define PIRQC	MPC83xx_IRQ_EXT6
 #define PIRQD	MPC83xx_IRQ_EXT7
 
-#endif                /* __MACH_MPC83XX_SYS_H__ */
+#endif				/* __MACH_MPC83XX_SYS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
index 228d5c4..01cae10 100644
--- a/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -14,4 +14,4 @@ extern int mpc83xx_exclude_device(u_char
 extern void mpc83xx_restart(char *cmd);
 extern long mpc83xx_time_init(void);
 
-#endif /* __MPC83XX_H__ */
+#endif				/* __MPC83XX_H__ */
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 70e28fc..16f7d3b 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -61,7 +61,7 @@ int __init add_bridge(struct device_node
 	has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
 
 	/* Get bus range if any */
-	bus_range = (int *) get_property(dev, "bus-range", &len);
+	bus_range = (int *)get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		printk(KERN_WARNING "Can't get bus-range for %s, assume"
 		       " bus 0\n", dev->full_name);
@@ -83,7 +83,7 @@ int __init add_bridge(struct device_node
 	if ((rsrc.start & 0xfffff) == 0x8500) {
 		setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304);
 	}
-	/* PCI 2*/
+	/* PCI 2 */
 	if ((rsrc.start & 0xfffff) == 0x8600) {
 		setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384);
 		primary = 0;
@@ -93,10 +93,10 @@ int __init add_bridge(struct device_node
 
 	printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%08lx. "
 	       "Firmware bus number: %d->%d\n",
-		rsrc.start, hose->first_busno, hose->last_busno);
+	       rsrc.start, hose->first_busno, hose->last_busno);
 
 	DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
-		hose, hose->cfg_addr, hose->cfg_data);
+	    hose, hose->cfg_addr, hose->cfg_data);
 
 	/* Interpret the "ranges" property */
 	/* This also maps the I/O region and sets isa_io/mem_base */

^ permalink raw reply related

* Re: opening the serial port from userspace application
From: Wolfgang Denk @ 2006-02-02 20:13 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: bharathi kandimalla, linuxppc-embedded
In-Reply-To: <20060202144520.3422129b@vitb.ru.mvista.com>

In message <20060202144520.3422129b@vitb.ru.mvista.com> you wrote:
>
> >From what I can see, you have misconfigured something. Dunno for certain, but 860T 
> might have 2 UARTs, when you have at least 4 enabled. Please enable in the kernel configuration only those which exist on your board.

You can have up to 6 UART ports on a 860 (2 x SMC + 4 x SCC).

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Don't tell me how hard you work.  Tell me how much you get done.
                                                     -- James J. Ling

^ permalink raw reply

* Re: SPI flash kernel 2.4 driver
From: Ron Kellam @ 2006-02-02 22:26 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <20060131211155.BF9193535E8@atlas.denx.de>

On Tue, 31 Jan 2006 22:11:55 +0100, Wolfgang Denk <wd@denx.de> wrote:

>The Katix SPI framework  is  integrated  with  our  2.4  kernel;  see
>drivers/spi

It might be integrated, but it's seriously broken.  IIRC, the whole
chip select mechanism is not working, and the code still has a lot of
I2Cisms about it.

Regards,
Ron

^ permalink raw reply

* Re: [PATCH] Add fec support for mpc52xx
From: Sylvain Munaut @ 2006-02-03  0:19 UTC (permalink / raw)
  To: Dale Farnsworth, linuxppc-embedded, jrigby
In-Reply-To: <20060202193734.22145.qmail@farnsworth.org>

Dale Farnsworth wrote:
> In article <43E24DA6.9@freescale.com> John Rigby wrote:
> 
>>Adds fec support, requires bestcom patch.  Applies to Sylvains git tree.
> 
> 
> Hmm, I thought that fec support was already in Sylvain's git tree.
> 
> I'm sure Sylvain intended it to be there.

Yup, after the recent updates that went upstream, I re-created more
cleanly my git tree. To keep it clean, I took my time to try out several
git feature and stuff before publishing result. For now the bcomm is
available as a patch and I posted the URL recently.

The splitted vesion should be uploaded tomorrow, I'll make sure I use
the latest microcode (compare with the one sent by John) but It's
getting late here.

If you don't get up too early, it should be done by the time you get up ;)


Sylvain

> 
> From http://ozlabs.org/pipermail/linuxppc-embedded/2005-June/018887.html:
> 
>>Date: Sun, 19 Jun 2005 00:15:32 +0200
>>From: Sylvain Munaut <tnt@246tNt.com>
>>
>>Following the obvious demand for it :
>>
>>rsync://gitbits.246tNt.com/gitbits/linux-2.6-mpc52xx.git
>>http://gitbits.246tNt.com/gitweb.cgi?p=linux-2.6-mpc52xx.git;a=summary
>>
>>Hopefully the server is setup correctly ...
>>It's not _heavily_ tested but it seems to works fine in the few test I
>>made.
>>
>>What in there :
>> - I2C patches that are already sent upstream but not yet in Linus tree
>> - Change of the mpc52xx uart device name and device ids to a range in
>>   the low density serial port major. Also it's now named ttyPSC? so
>>   you need to update you kernel command line (else you won't see any
>>   console). Note that the ids and names choosed are NOT YET OFFICIAL,
>>   I just included it in this release because some people were seeing
>>   conflict with the other ids. So the name and ids may change ...
>> - Some other patches that will soon be sent upstream, just waiting
>>   for you to test see if it has any negative impact.
>> - FEC and BestComm rewrite from Dale, with some improvement. For eg,
>>   the FEC task now handle misaligment so the manual alignment code
>>   has been removed, ...
> 
> 
> I hope Sylvain can resurrect the 2.6 FEC code that he, I and others
> worked on.
> 
> -Dale
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> 

^ permalink raw reply

* [PATCH] fix generic_fls64()
From: Akinobu Mita @ 2006-02-03  1:27 UTC (permalink / raw)
  To: Rune Torgersen
  Cc: akpm, linux-mips, linux-ia64, Stephen Hemminger, 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-m68k, linux-kernel,
	linuxsh-shmedia-dev, linux390, Russell King, parisc-linux
In-Reply-To: <DCEAAC0833DD314AB0B58112AD99B93B859547@ismail.innsys.innovsys.com>

Noticed by Rune Torgersen.

fix generic_fls64().
tcp_cubic is using fls64().

Signed-off-by: Akinobu Mita <mita@miraclelinux.com>

 include/linux/bitops.h |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

Index: 2.6-git/include/linux/bitops.h
===================================================================
--- 2.6-git.orig/include/linux/bitops.h
+++ 2.6-git/include/linux/bitops.h
@@ -81,7 +81,7 @@ static inline int generic_fls64(__u64 x)
 {
 	__u32 h = x >> 32;
 	if (h)
-		return fls(x) + 32;
+		return fls(h) + 32;
 	return fls(x);
 }
 

^ permalink raw reply

* [PATCH] powerpc: Add missing vmlinux.bin target
From: Geoff Levand @ 2006-02-02 23:41 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Kumar Gala, linuxppc-dev
In-Reply-To: <Pine.LNX.4.44.0511231242510.4183-100000@gate.crashing.org>

With this patch 'make vmlinux.bin' works.  This is needed by
some embedded platforms.  Kumar already added the routines
to actually build the image in arch/powerpc/boot/Makefile.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>

--


Index: powerpc-merge.git/arch/powerpc/Makefile
===================================================================
--- powerpc-merge.git.orig/arch/powerpc/Makefile	2006-02-02 15:23:03.000000000 -0800
+++ powerpc-merge.git/arch/powerpc/Makefile	2006-02-02 15:23:53.000000000 -0800
@@ -147,7 +147,7 @@

 CPPFLAGS_vmlinux.lds	:= -Upowerpc

-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage
+BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin

 .PHONY: $(BOOT_TARGETS)

^ permalink raw reply

* test
From: Stephen Rothwell @ 2006-02-03  3:31 UTC (permalink / raw)
  To: linuxppc-embedded

Please ignore

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

^ permalink raw reply

* Re: [parisc-linux] [patch 12/44] generic sched_find_first_bit()
From: Grant Grundler @ 2006-02-03  3:58 UTC (permalink / raw)
  To: Akinobu Mita
  Cc: linux-mips, linux-ia64, Ian Molton, Andi Kleen, David Howells,
	linuxppc-dev, Greg Ungerer, sparclinux, Miles Bader,
	Yoshinori Sato, Hirokazu Takata, linuxsh-shmedia-dev,
	Linus Torvalds, Chris Zankel, dev-etrax, ultralinux, linux-m68k,
	linux-kernel, linuxsh-dev, linux390, Russell King, parisc-linux
In-Reply-To: <20060201090325.497639000@localhost.localdomain>

On Wed, Feb 01, 2006 at 06:02:36PM +0900, Akinobu Mita wrote:
> This patch introduces the C-language equivalent of the function:
> int sched_find_first_bit(const unsigned long *b);

Akinobu, would you prefer this is a slightly cleaner way?
(Not compile tested)

static inline int sched_find_first_bit(const unsigned long *b)
{
	if (unlikely(b[0]))
		return __ffs(b[0]);
	if (unlikely(b[1]))
		return __ffs(b[1]) + BITS_PER_LONG;
#if BITS_PER_LONG == 32
	if (unlikely(b[2]))
		return __ffs(b[2]) + 64;
	if (b[3])
		return __ffs(b[3]) + 96;
#endif
	return __ffs(b[128/BITS_PER_LONG]) + 128;
}

If BITS_PER_LONG isn't defined, the link step will fail and point
at a some unknown .o as the offender. But it's the responsibility
of the header file to make sure it's including the BITS_PER_LONG
definition, not the code that calls sched_find_first_bit().

hth,
grant

^ permalink raw reply

* Re: spinlockup detection on POWER3
From: Olaf Hering @ 2006-02-03  8:04 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20060122083826.GA5292@suse.de>

 On Sun, Jan 22, Olaf Hering wrote:

> Does the CONFIG_DEBUG_SPINLOCK code  somehow depend on the cpu type?
> It triggers alot on a p270 POWER3 box, even during early boot. I dont 
> see it on POWE4/5.

> BUG: spinlock lockup on CPU#3, hotplug/1384, c000000000456900
...

this was cause by per_cpu data corruption.

-- 
short story of a lazy sysadmin:
 alias appserv=wotan

^ permalink raw reply

* Re: [patch 14/44] generic hweight{64,32,16,8}()
From: Ulrich Eckhardt @ 2006-02-03  8:31 UTC (permalink / raw)
  To: Akinobu Mita
  Cc: linux-mips, 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-m68k, linux-kernel, linuxsh-shmedia-dev,
	linux390, Russell King, parisc-linux
In-Reply-To: <20060201090325.905071000@localhost.localdomain>

On Wednesday 01 February 2006 10:02, Akinobu Mita wrote:
> unsigned int hweight32(unsigned int w);
> unsigned int hweight16(unsigned int w);
> unsigned int hweight8(unsigned int w);
> unsigned long hweight64(__u64 w);

IMHO, this should use explicitly sized integers like __u8, __u16 etc, unless 
there are stringent reasons like better register use - which is hard to tell 
for generic C code. Also, why on earth is the returntype for hweight64 a 
long?

> +static inline unsigned int hweight32(unsigned int w)
> +{
> +        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
> +        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
[...]

Why not use unsigned constants here?

> +static inline unsigned long hweight64(__u64 w)
> +{
[..]
> +	u64 res;
> +	res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);

Why not use initialisation here, too?

just my 2c

Uli

^ permalink raw reply

* How to cross-build OpenSSL shared library
From: Marc.Bodmer @ 2006-02-03  9:45 UTC (permalink / raw)
  To: linuxppc-embedded

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


Hello

I have a problem with cross compiling the OpenSSL library for PPC (mpc885) as a
shared library (Host x86, Linux).

I give the option "shared" to the "Configure" script delivered with OpenSSL. But it
always only builds me static libraries. After Configuration it shows me the text:

>You gave the option 'shared'. Normally, that would give you shared libraries.
>Unfortunately, the OpenSSL configuration doesn't include shared library support
>for this platform yet, so it will pretend you gave the option 'no-shared'

I am using ELDK (3.1.1) and there is a built OpenSSL as shared library
available.
Does anybody know about how they managed to build this shared library?

Thanks for any help
Marc
























<html>
<body>
<font face = "arial" size = "1">
---------------------------------------------------------------------------------------------------------
This e-mail is confidential and may contain privileged information.
It is intended only for the addressees. If you have received this
e-mail in error, kindly notify us immediately by telephone or e-mail
and delete the message from your system.
---------------------------------------------------------------------------------------------------------
</font>
</body>
</html>

[-- Attachment #2: Type: text/html, Size: 5156 bytes --]

^ permalink raw reply

* CPM2 USB driver & MPC8248
From: Laurent Pinchart @ 2006-02-03 11:10 UTC (permalink / raw)
  To: mike; +Cc: linuxppc-embedded

Hi Mike,

I'm having trouble using your CPM2 USB host controller driver on an Embedded 
Planet EP8248 board with Linux 2.6.15.

The driver didn't compiler with 2.6.15 but the required changes were minor 
(the root hub doesn't have to be registered by the host controller driver 
anymore, and a few functions have been renamed). I modified the board setup 
function according to my hardware (different BCSR registers) and the driver 
loads properly.

When I connect a USB 2.0 Mass Storage device, initialization fails when trying 
to fetch the string descriptors. Here's what USBMon produces (I decoded the 
USB transactions with the device).

/* Initialization */
c054a860 62948014 C Ii:001:01 0 1 D
c054a860 62948089 S Ii:001:01 -115 2 D
c04500e0 62948126 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 62948134 C Ci:001:00 0 4 = 01010100
c04500e0 62948146 S Co:001:00 s 23 01 0010 0001 0000 0
c04500e0 62948151 C Co:001:00 0 0
c04500e0 62948158 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 62948163 C Ci:001:00 0 4 = 01010000
c04500e0 62980027 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 62980045 C Ci:001:00 0 4 = 01010000
c04500e0 63012025 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 63012042 C Ci:001:00 0 4 = 01010000
c04500e0 63044025 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 63044042 C Ci:001:00 0 4 = 01010000
c04500e0 63076025 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 63076043 C Ci:001:00 0 4 = 01010000
c04500e0 63076088 S Co:001:00 s 23 03 0004 0001 0000 0
c04500e0 63172013 C Co:001:00 0 0
c04500e0 63228024 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 63228042 C Ci:001:00 0 4 = 03010000
c04500e0 63284035 S Co:001:00 s 23 01 0014 0001 0000 0
c04500e0 63284052 C Co:001:00 0 0
c04500e0 63456779 S Ci:000:00 s 80 06 0100 0000 0040 64 <
c04500e0 63457301 C Ci:000:00 0 18 = 12010002 00000040 81075051 20000102 0301
c04500e0 63457338 S Co:001:00 s 23 03 0004 0001 0000 0
c04500e0 63552013 C Co:001:00 0 0
c04500e0 63608025 S Ci:001:00 s a3 00 0000 0001 0004 4 <
c04500e0 63608043 C Ci:001:00 0 4 = 03010000
c04500e0 63664025 S Co:001:00 s 23 01 0014 0001 0000 0
c04500e0 63664042 C Co:001:00 0 0
c04500e0 63664055 S Co:000:00 s 00 05 0002 0000 0000 0
c04500e0 63664590 C Co:000:00 0 0

/* GET_DESCRIPTOR DEVICE 0x12 bytes */
c04500e0 63680039 S Ci:002:00 s 80 06 0100 0000 0012 18 <
c04500e0 63680781 C Ci:002:00 0 18 = 12010002 00000040 81075051 20000102 0301

/* GET_DESCRIPTOR CONFIGURATION 0x09 bytes */
c04500e0 63680825 S Ci:002:00 s 80 06 0200 0000 0009 9 <
c04500e0 63681795 C Ci:002:00 0 9 = 09022000 01010080 32

/* GET_DESCRIPTOR CONFIGURATION 0x20 bytes */
c04500e0 63681832 S Ci:002:00 s 80 06 0200 0000 0020 32 <
c04500e0 63682820 C Ci:002:00 0 32 = 09022000 01010080 32090400 00020806 
50000705 81024000 00070501 02400000

/* GET_DESCRIPTOR STRING 0xff bytes */
c0450140 63682877 S Ci:002:00 s 80 06 0300 0000 00ff 255 <
c0450140 68680032 C Ci:002:00 -104 0
/* GET_DESCRIPTOR STRING 0x02 bytes */
c0450140 68680075 S Ci:002:00 s 80 06 0300 0000 0002 2 <
c0450140 73680032 C Ci:002:00 -104 0
/* GET_DESCRIPTOR STRING 0xff bytes */
c0450140 73725213 S Ci:002:00 s 80 06 0300 0000 00ff 255 <
c0450140 78724036 C Ci:002:00 -104 0
/* GET_DESCRIPTOR STRING 0x02 bytes */
c0450140 78724141 S Ci:002:00 s 80 06 0300 0000 0002 2 <
c0450140 83724019 C Ci:002:00 -104 0
/* GET_DESCRIPTOR STRING 0xff bytes */
c0450140 83769592 S Ci:002:00 s 80 06 0300 0000 00ff 255 <
c0450140 88768017 C Ci:002:00 -104 0
/* GET_DESCRIPTOR STRING 0x02 bytes */
c0450140 88768053 S Ci:002:00 s 80 06 0300 0000 0002 2 <
c0450140 93768016 C Ci:002:00 -104 0

/* SET_CONFIGURATION 1 */
c0450140 93814145 S Co:002:00 s 00 09 0001 0000 0000 0
c0450140 98812017 C Co:002:00 -104 0

As you can see, the devices sends its device and configuration descriptors, 
but something goes wrong with the string descriptors. I modified the core USB 
code to request 0x40 bytes (which is the value of bMaxPacketSize0) or even 
0x20 bytes, but the same problem occurs (same USBMon traces with 0xff 
replaced by 0x40).

Could you help me ? Kernel coding is not a problem, so I can make experiments 
if you point me to some direction. I'm also quite familiar with the USB specs 
down to the various types of transfers (control, interrupt, bulk and 
isochronous) but not with the lower-level protocol (frames, tokens, ...). I 
can learn if needed.

Laurent Pinchart

^ permalink raw reply

* Re: CPM2 USB driver & MPC8248
From: Laurent Pinchart @ 2006-02-03 11:34 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <200602031210.12603.laurent.pinchart@tbox.biz>

Hi,

after more testing, I found out that only the first 3 control URBs complete 
successfully. I tried to duplicate the first GET_DESCRIPTOR(CONFIG) request, 
and the second one which worked before now fails. If I unplug/replug the 
device, the first GET_DESCRIPTOR(DEVICE) request sent to device 0 from 
hub_port_init fails:

c0450260 133702068 S Ci:000:00 s 80 06 0100 0000 0040 64 <
c0450260 134700018 C Ci:000:00 -104 0
c0450260 134700053 S Ci:000:00 s 80 06 0100 0000 0040 64 <
c0450260 135700016 C Ci:000:00 -104 0
c0450260 135700049 S Ci:000:00 s 80 06 0100 0000 0040 64 <
c0450260 136700018 C Ci:000:00 -104 0

Hope this helps to diagnose the problem,

Laurent Pinchart

^ 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