linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] PAL: Support of the fixed PHY
       [not found] <20060623231648.6721.3495.stgit@localhost.localdomain>
@ 2006-06-23 23:16 ` Vitaly Bordug
  2006-06-23 23:16 ` [PATCH 2/6] FS_ENET: Utilize Phy abstraction Vitaly Bordug
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-23 23:16 UTC (permalink / raw)
  To: linuxppc-dev


This makes it possible for HW PHY-less boards to utilize PAL goodies.
Generic routines to connect to fixed PHY are provided, as well as ability
to specify software callback that fills up link, speed, etc. information
into PHY descriptor (the latter feature not tested so far).

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
---

 drivers/net/phy/Kconfig      |   17 ++++++++++++++
 drivers/net/phy/phy_device.c |   51 +++++++++++++++++++++++++-----------------
 include/linux/phy.h          |    1 +
 3 files changed, 48 insertions(+), 21 deletions(-)

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 76e51b1..e977fe1 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -50,5 +50,22 @@ config VITESSE_PHY
         ---help---
           Currently supports the vsc8244
 
+config FIXED_PHY
+	tristate "Drivers for PHY emulation on fixed speed/link"
+	depends on PHYLIB
+	---help---
+	  Adds the driver to PHY layer to cover the boards that do not have any PHY bound,
+	  but with the ability to manipulate with speed/link in software. The relavant MII
+	  speed/duplex parameters could be effectively handled in user-specified  fuction.
+	  Currently tested with mpc866ads.
+
+config FIXED_MII_10_FDX
+	bool "Emulation for 10M Fdx fixed PHY behavior"
+	depends on FIXED_PHY
+
+config FIXED_MII_100_FDX
+	bool "Emulation for 100M Fdx fixed PHY behavior"
+	depends on FIXED_PHY
+
 endmenu
 
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 7da0e3d..dfdafe9 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -46,6 +46,35 @@ static struct phy_driver genphy_driver;
 extern int mdio_bus_init(void);
 extern void mdio_bus_exit(void);
 
+struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
+{
+	struct phy_device *dev;
+	/* We allocate the device, and initialize the
+	 * default values */
+	dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
+
+	if (NULL == dev)
+		return PTR_ERR(-ENOMEM);
+
+	dev->speed = 0;
+	dev->duplex = -1;
+	dev->pause = dev->asym_pause = 0;
+	dev->link = 1;
+
+	dev->autoneg = AUTONEG_ENABLE;
+
+	dev->addr = addr;
+	dev->phy_id = phy_id;
+	dev->bus = bus;
+
+	dev->state = PHY_DOWN;
+
+	spin_lock_init(&dev->lock);
+
+	return dev;
+}
+EXPORT_SYMBOL(phy_device_create);
+
 /* get_phy_device
  *
  * description: Reads the ID registers of the PHY at addr on the
@@ -78,28 +107,8 @@ struct phy_device * get_phy_device(struc
 	/* If the phy_id is all Fs, there is no device there */
 	if (0xffffffff == phy_id)
 		return NULL;
-
-	/* Otherwise, we allocate the device, and initialize the
-	 * default values */
-	dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
 
-	if (NULL == dev)
-		return ERR_PTR(-ENOMEM);
-
-	dev->speed = 0;
-	dev->duplex = -1;
-	dev->pause = dev->asym_pause = 0;
-	dev->link = 1;
-
-	dev->autoneg = AUTONEG_ENABLE;
-
-	dev->addr = addr;
-	dev->phy_id = phy_id;
-	dev->bus = bus;
-
-	dev->state = PHY_DOWN;
-
-	spin_lock_init(&dev->lock);
+	dev = phy_device_create(bus, addr, phy_id);
 
 	return dev;
 }
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 331521a..9447a57 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -378,6 +378,7 @@ int phy_mii_ioctl(struct phy_device *phy
 		struct mii_ioctl_data *mii_data, int cmd);
 int phy_start_interrupts(struct phy_device *phydev);
 void phy_print_status(struct phy_device *phydev);
+struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id);
 
 extern struct bus_type mdio_bus_type;
 #endif /* __PHY_H */

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/6] FS_ENET: Utilize Phy abstraction
       [not found] <20060623231648.6721.3495.stgit@localhost.localdomain>
  2006-06-23 23:16 ` [PATCH 1/6] PAL: Support of the fixed PHY Vitaly Bordug
@ 2006-06-23 23:16 ` Vitaly Bordug
  2006-06-23 23:17 ` [PATCH 3/6] FS_ENET: use PAL for mii management (BSP part) Vitaly Bordug
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-23 23:16 UTC (permalink / raw)
  To: linuxppc-dev


This part has modifications necessary to make fs_enet use Phy Abstraction
Layer. All mdio trasports were supported, including FEC and bitbanging via
GPIO.

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
---

 drivers/net/fs_enet/Makefile       |    6 
 drivers/net/fs_enet/fec.h          |   42 +++
 drivers/net/fs_enet/fs_enet-main.c |  207 +++++++++------
 drivers/net/fs_enet/fs_enet-mii.c  |  507 ------------------------------------
 drivers/net/fs_enet/fs_enet.h      |   40 ++-
 drivers/net/fs_enet/mac-fcc.c      |   32 ++
 drivers/net/fs_enet/mac-fec.c      |  132 +--------
 drivers/net/fs_enet/mac-scc.c      |    4 
 drivers/net/fs_enet/mii-bitbang.c  |  462 +++++++++++++++++----------------
 drivers/net/fs_enet/mii-fec.c      |  243 +++++++++++++++++
 drivers/net/fs_enet/mii-fixed.c    |   92 -------
 11 files changed, 713 insertions(+), 1054 deletions(-)

diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile
index d6dd3f2..02d4dc1 100644
--- a/drivers/net/fs_enet/Makefile
+++ b/drivers/net/fs_enet/Makefile
@@ -4,7 +4,7 @@ #
 
 obj-$(CONFIG_FS_ENET) += fs_enet.o
 
-obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o
-obj-$(CONFIG_8260) += mac-fcc.o
+obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o mii-fec.o
+obj-$(CONFIG_CPM2) += mac-fcc.o mii-bitbang.o
 
-fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o
+fs_enet-objs := fs_enet-main.o
diff --git a/drivers/net/fs_enet/fec.h b/drivers/net/fs_enet/fec.h
new file mode 100644
index 0000000..e980527
--- /dev/null
+++ b/drivers/net/fs_enet/fec.h
@@ -0,0 +1,42 @@
+#ifndef FS_ENET_FEC_H
+#define FS_ENET_FEC_H
+
+/* CRC polynomium used by the FEC for the multicast group filtering */
+#define FEC_CRC_POLY   0x04C11DB7
+
+#define FEC_MAX_MULTICAST_ADDRS	64
+
+/* Interrupt events/masks.
+*/
+#define FEC_ENET_HBERR	0x80000000U	/* Heartbeat error          */
+#define FEC_ENET_BABR	0x40000000U	/* Babbling receiver        */
+#define FEC_ENET_BABT	0x20000000U	/* Babbling transmitter     */
+#define FEC_ENET_GRA	0x10000000U	/* Graceful stop complete   */
+#define FEC_ENET_TXF	0x08000000U	/* Full frame transmitted   */
+#define FEC_ENET_TXB	0x04000000U	/* A buffer was transmitted */
+#define FEC_ENET_RXF	0x02000000U	/* Full frame received      */
+#define FEC_ENET_RXB	0x01000000U	/* A buffer was received    */
+#define FEC_ENET_MII	0x00800000U	/* MII interrupt            */
+#define FEC_ENET_EBERR	0x00400000U	/* SDMA bus error           */
+
+#define FEC_ECNTRL_PINMUX	0x00000004
+#define FEC_ECNTRL_ETHER_EN	0x00000002
+#define FEC_ECNTRL_RESET	0x00000001
+
+#define FEC_RCNTRL_BC_REJ	0x00000010
+#define FEC_RCNTRL_PROM		0x00000008
+#define FEC_RCNTRL_MII_MODE	0x00000004
+#define FEC_RCNTRL_DRT		0x00000002
+#define FEC_RCNTRL_LOOP		0x00000001
+
+#define FEC_TCNTRL_FDEN		0x00000004
+#define FEC_TCNTRL_HBC		0x00000002
+#define FEC_TCNTRL_GTS		0x00000001
+
+
+
+/*
+ * Delay to wait for FEC reset command to complete (in us)
+ */
+#define FEC_RESET_DELAY		50
+#endif
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 196298f..302ecaa 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -38,6 +38,7 @@ #include <linux/ethtool.h>
 #include <linux/bitops.h>
 #include <linux/fs.h>
 #include <linux/platform_device.h>
+#include <linux/phy.h>
 
 #include <linux/vmalloc.h>
 #include <asm/pgtable.h>
@@ -683,35 +684,6 @@ static void fs_free_irq(struct net_devic
 	(*fep->ops->post_free_irq)(dev, irq);
 }
 
-/**********************************************************************************/
-
-/* This interrupt occurs when the PHY detects a link change. */
-static irqreturn_t
-fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = dev_id;
-	struct fs_enet_private *fep;
-	const struct fs_platform_info *fpi;
-
-	fep = netdev_priv(dev);
-	fpi = fep->fpi;
-
-	/*
-	 * Acknowledge the interrupt if possible. If we have not
-	 * found the PHY yet we can't process or acknowledge the
-	 * interrupt now. Instead we ignore this interrupt for now,
-	 * which we can do since it is edge triggered. It will be
-	 * acknowledged later by fs_enet_open().
-	 */
-	if (!fep->phy)
-		return IRQ_NONE;
-
-	fs_mii_ack_int(dev);
-	fs_mii_link_status_change_check(dev, 0);
-
-	return IRQ_HANDLED;
-}
-
 static void fs_timeout(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
@@ -723,67 +695,146 @@ static void fs_timeout(struct net_device
 	spin_lock_irqsave(&fep->lock, flags);
 
 	if (dev->flags & IFF_UP) {
+		phy_stop(fep->phydev);
 		(*fep->ops->stop)(dev);
 		(*fep->ops->restart)(dev);
+		phy_start(fep->phydev);
 	}
 
+	phy_start(fep->phydev);
 	wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY);
 	spin_unlock_irqrestore(&fep->lock, flags);
 
 	if (wake)
 		netif_wake_queue(dev);
+}
+
+/*-----------------------------------------------------------------------------
+ *  generic link-change handler - should be sufficient for most cases
+ *-----------------------------------------------------------------------------*/
+static void generic_adjust_link(struct  net_device *dev)
+{
+       struct fs_enet_private *fep = netdev_priv(dev);
+       struct phy_device *phydev = fep->phydev;
+       int new_state = 0;
+
+       if (phydev->link) {
+
+               /* adjust to duplex mode */
+               if (phydev->duplex != fep->oldduplex){
+                       new_state = 1;
+                       fep->oldduplex = phydev->duplex;
+               }
+
+               if (phydev->speed != fep->oldspeed) {
+                       new_state = 1;
+                       fep->oldspeed = phydev->speed;
+               }
+
+               if (!fep->oldlink) {
+                       new_state = 1;
+                       fep->oldlink = 1;
+                       netif_schedule(dev);
+                       netif_carrier_on(dev);
+                       netif_start_queue(dev);
+               }
+
+               if (new_state)
+                       fep->ops->restart(dev);
+
+       } else if (fep->oldlink) {
+               new_state = 1;
+               fep->oldlink = 0;
+               fep->oldspeed = 0;
+               fep->oldduplex = -1;
+               netif_carrier_off(dev);
+               netif_stop_queue(dev);
+       }
+
+       if (new_state && netif_msg_link(fep))
+               phy_print_status(phydev);
+}
+
+
+static void fs_adjust_link(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fep->lock, flags);
+
+	if(fep->ops->adjust_link)
+		fep->ops->adjust_link(dev);
+	else
+		generic_adjust_link(dev);
+
+	spin_unlock_irqrestore(&fep->lock, flags);
+}
+
+static int fs_init_phy(struct net_device *dev)
+{
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct phy_device *phydev;
+
+	fep->oldlink = 0;
+	fep->oldspeed = 0;
+	fep->oldduplex = -1;
+	if(fep->fpi->bus_id)
+		phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0);
+	else {
+		printk("No phy bus ID specified in BSP code\n");
+		return -EINVAL;
+	}
+	if (IS_ERR(phydev)) {
+		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+
+	fep->phydev = phydev;
+
+	return 0;
 }
 
+
 static int fs_enet_open(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	const struct fs_platform_info *fpi = fep->fpi;
 	int r;
+	int err;
 
 	/* Install our interrupt handler. */
 	r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
 	if (r != 0) {
 		printk(KERN_ERR DRV_MODULE_NAME
-		       ": %s Could not allocate FEC IRQ!", dev->name);
+		       ": %s Could not allocate FS_ENET IRQ!", dev->name);
 		return -EINVAL;
 	}
 
-	/* Install our phy interrupt handler */
-	if (fpi->phy_irq != -1) {
+	err = fs_init_phy(dev);
+	if(err)
+		return err;
 
-		r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt);
-		if (r != 0) {
-			printk(KERN_ERR DRV_MODULE_NAME
-			       ": %s Could not allocate PHY IRQ!", dev->name);
-			fs_free_irq(dev, fep->interrupt);
-			return -EINVAL;
-		}
-	}
+	phy_start(fep->phydev);
 
-	fs_mii_startup(dev);
-	netif_carrier_off(dev);
-	fs_mii_link_status_change_check(dev, 1);
-
 	return 0;
 }
 
 static int fs_enet_close(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	const struct fs_platform_info *fpi = fep->fpi;
 	unsigned long flags;
 
 	netif_stop_queue(dev);
 	netif_carrier_off(dev);
-	fs_mii_shutdown(dev);
+	phy_stop(fep->phydev);
 
 	spin_lock_irqsave(&fep->lock, flags);
 	(*fep->ops->stop)(dev);
 	spin_unlock_irqrestore(&fep->lock, flags);
 
 	/* release any irqs */
-	if (fpi->phy_irq != -1)
-		fs_free_irq(dev, fpi->phy_irq);
+	phy_disconnect(fep->phydev);
+	fep->phydev = NULL;
 	fs_free_irq(dev, fep->interrupt);
 
 	return 0;
@@ -831,33 +882,19 @@ static void fs_get_regs(struct net_devic
 static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	unsigned long flags;
-	int rc;
-
-	spin_lock_irqsave(&fep->lock, flags);
-	rc = mii_ethtool_gset(&fep->mii_if, cmd);
-	spin_unlock_irqrestore(&fep->lock, flags);
-
-	return rc;
+	return phy_ethtool_gset(fep->phydev, cmd);
 }
 
 static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	unsigned long flags;
-	int rc;
-
-	spin_lock_irqsave(&fep->lock, flags);
-	rc = mii_ethtool_sset(&fep->mii_if, cmd);
-	spin_unlock_irqrestore(&fep->lock, flags);
-
-	return rc;
+	phy_ethtool_sset(fep->phydev, cmd);
+	return 0;
 }
 
 static int fs_nway_reset(struct net_device *dev)
 {
-	struct fs_enet_private *fep = netdev_priv(dev);
-	return mii_nway_restart(&fep->mii_if);
+	return 0;
 }
 
 static u32 fs_get_msglevel(struct net_device *dev)
@@ -899,7 +936,7 @@ static int fs_ioctl(struct net_device *d
 		return -EINVAL;
 
 	spin_lock_irqsave(&fep->lock, flags);
-	rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL);
+	rc = phy_mii_ioctl(fep->phydev, mii, cmd);
 	spin_unlock_irqrestore(&fep->lock, flags);
 	return rc;
 }
@@ -1031,12 +1068,6 @@ #endif
 	}
 	registered = 1;
 
-	err = fs_mii_connect(ndev);
-	if (err != 0) {
-		printk(KERN_ERR DRV_MODULE_NAME
-		       ": %s fs_mii_connect failed.\n", ndev->name);
-		goto err;
-	}
 
 	return ndev;
 
@@ -1073,8 +1104,6 @@ static int fs_cleanup_instance(struct ne
 		return -EINVAL;
 
 	fpi = fep->fpi;
-
-	fs_mii_disconnect(ndev);
 
 	unregister_netdev(ndev);
 
@@ -1197,17 +1226,39 @@ static int __init fs_init(void)
 	r = setup_immap();
 	if (r != 0)
 		return r;
-	r = driver_register(&fs_enet_fec_driver);
+
+#ifdef CONFIG_FS_ENET_HAS_FCC
+	/* let's insert mii stuff */
+	r = fs_enet_mdio_bb_init();
+
+	if (r != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+			"BB PHY init failed.\n");
+		return r;
+	}
+	r = driver_register(&fs_enet_fcc_driver);
 	if (r != 0)
 		goto err;
+#endif
 
-	r = driver_register(&fs_enet_fcc_driver);
+#ifdef CONFIG_FS_ENET_HAS_FEC
+	r =  fs_enet_mdio_fec_init();
+	if (r != 0) {
+		printk(KERN_ERR DRV_MODULE_NAME
+			"FEC PHY init failed.\n");
+		return r;
+	}
+
+	r = driver_register(&fs_enet_fec_driver);
 	if (r != 0)
 		goto err;
+#endif
 
+#ifdef CONFIG_FS_ENET_HAS_SCC
 	r = driver_register(&fs_enet_scc_driver);
 	if (r != 0)
 		goto err;
+#endif
 
 	return 0;
 err:
diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c
deleted file mode 100644
index c677037..0000000
--- a/drivers/net/fs_enet/fs_enet-mii.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
- *
- * Copyright (c) 2003 Intracom S.A. 
- *  by Pantelis Antoniou <panto@intracom.gr>
- * 
- * 2005 (c) MontaVista Software, Inc. 
- * Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
- * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
- *
- * 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.
- */
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "fs_enet.h"
-
-/*************************************************/
-
-/*
- * Generic PHY support.
- * Should work for all PHYs, but link change is detected by polling
- */
-
-static void generic_timer_callback(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	fep->phy_timer_list.expires = jiffies + HZ / 2;
-
-	add_timer(&fep->phy_timer_list);
-
-	fs_mii_link_status_change_check(dev, 0);
-}
-
-static void generic_startup(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	fep->phy_timer_list.expires = jiffies + HZ / 2;	/* every 500ms */
-	fep->phy_timer_list.data = (unsigned long)dev;
-	fep->phy_timer_list.function = generic_timer_callback;
-	add_timer(&fep->phy_timer_list);
-}
-
-static void generic_shutdown(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	del_timer_sync(&fep->phy_timer_list);
-}
-
-/* ------------------------------------------------------------------------- */
-/* The Davicom DM9161 is used on the NETTA board			     */
-
-/* register definitions */
-
-#define MII_DM9161_ANAR		4	/* Aux. Config Register         */
-#define MII_DM9161_ACR		16	/* Aux. Config Register         */
-#define MII_DM9161_ACSR		17	/* Aux. Config/Status Register  */
-#define MII_DM9161_10TCSR	18	/* 10BaseT Config/Status Reg.   */
-#define MII_DM9161_INTR		21	/* Interrupt Register           */
-#define MII_DM9161_RECR		22	/* Receive Error Counter Reg.   */
-#define MII_DM9161_DISCR	23	/* Disconnect Counter Register  */
-
-static void dm9161_startup(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
-	/* Start autonegotiation */
-	fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200);
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ*8);
-}
-
-static void dm9161_ack_int(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
-}
-
-static void dm9161_shutdown(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
-}
-
-/**********************************************************************************/
-
-static const struct phy_info phy_info[] = {
-	{
-		.id = 0x00181b88,
-		.name = "DM9161",
-		.startup = dm9161_startup,
-		.ack_int = dm9161_ack_int,
-		.shutdown = dm9161_shutdown,
-	}, {
-		.id = 0,
-		.name = "GENERIC",
-		.startup = generic_startup,
-		.shutdown = generic_shutdown,
-	},
-};
-
-/**********************************************************************************/
-
-static int phy_id_detect(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-	const struct fs_platform_info *fpi = fep->fpi;
-	struct fs_enet_mii_bus *bus = fep->mii_bus;
-	int i, r, start, end, phytype, physubtype;
-	const struct phy_info *phy;
-	int phy_hwid, phy_id;
-
-	phy_hwid = -1;
-	fep->phy = NULL;
-
-	/* auto-detect? */
-	if (fpi->phy_addr == -1) {
-		start = 1;
-		end = 32;
-	} else {		/* direct */
-		start = fpi->phy_addr;
-		end = start + 1;
-	}
-
-	for (phy_id = start; phy_id < end; phy_id++) {
-		/* skip already used phy addresses on this bus */ 
-		if (bus->usage_map & (1 << phy_id))
-			continue;
-		r = fs_mii_read(dev, phy_id, MII_PHYSID1);
-		if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
-			continue;
-		r = fs_mii_read(dev, phy_id, MII_PHYSID2);
-		if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
-			continue;
-		phy_hwid = (phytype << 16) | physubtype;
-		if (phy_hwid != -1)
-			break;
-	}
-
-	if (phy_hwid == -1) {
-		printk(KERN_ERR DRV_MODULE_NAME
-		       ": %s No PHY detected! range=0x%02x-0x%02x\n",
-			dev->name, start, end);
-		return -1;
-	}
-
-	for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
-		if (phy->id == (phy_hwid >> 4) || phy->id == 0)
-			break;
-
-	if (i >= ARRAY_SIZE(phy_info)) {
-		printk(KERN_ERR DRV_MODULE_NAME
-		       ": %s PHY id 0x%08x is not supported!\n",
-		       dev->name, phy_hwid);
-		return -1;
-	}
-
-	fep->phy = phy;
-
-	/* mark this address as used */
-	bus->usage_map |= (1 << phy_id);
-
-	printk(KERN_INFO DRV_MODULE_NAME
-	       ": %s Phy @ 0x%x, type %s (0x%08x)%s\n",
-	       dev->name, phy_id, fep->phy->name, phy_hwid,
-	       fpi->phy_addr == -1 ? " (auto-detected)" : "");
-
-	return phy_id;
-}
-
-void fs_mii_startup(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	if (fep->phy->startup)
-		(*fep->phy->startup) (dev);
-}
-
-void fs_mii_shutdown(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	if (fep->phy->shutdown)
-		(*fep->phy->shutdown) (dev);
-}
-
-void fs_mii_ack_int(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-
-	if (fep->phy->ack_int)
-		(*fep->phy->ack_int) (dev);
-}
-
-#define MII_LINK	0x0001
-#define MII_HALF	0x0002
-#define MII_FULL	0x0004
-#define MII_BASE4	0x0008
-#define MII_10M		0x0010
-#define MII_100M	0x0020
-#define MII_1G		0x0040
-#define MII_10G		0x0080
-
-/* return full mii info at one gulp, with a usable form */
-static unsigned int mii_full_status(struct mii_if_info *mii)
-{
-	unsigned int status;
-	int bmsr, adv, lpa, neg;
-	struct fs_enet_private* fep = netdev_priv(mii->dev);
-	
-	/* first, a dummy read, needed to latch some MII phys */
-	(void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
-	bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
-
-	/* no link */
-	if ((bmsr & BMSR_LSTATUS) == 0)
-		return 0;
-
-	status = MII_LINK;
-	
-	/* Lets look what ANEG says if it's supported - otherwize we shall
-	   take the right values from the platform info*/
-	if(!mii->force_media) {
-		/* autoneg not completed; don't bother */
-		if ((bmsr & BMSR_ANEGCOMPLETE) == 0)
-			return 0;
-
-		adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE);
-		lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA);
-
-		neg = lpa & adv;
-	} else {
-		neg = fep->fpi->bus_info->lpa;
-	}
-
-	if (neg & LPA_100FULL)
-		status |= MII_FULL | MII_100M;
-	else if (neg & LPA_100BASE4)
-		status |= MII_FULL | MII_BASE4 | MII_100M;
-	else if (neg & LPA_100HALF)
-		status |= MII_HALF | MII_100M;
-	else if (neg & LPA_10FULL)
-		status |= MII_FULL | MII_10M;
-	else
-		status |= MII_HALF | MII_10M;
-	
-	return status;
-}
-
-void fs_mii_link_status_change_check(struct net_device *dev, int init_media)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-	struct mii_if_info *mii = &fep->mii_if;
-	unsigned int mii_status;
-	int ok_to_print, link, duplex, speed;
-	unsigned long flags;
-
-	ok_to_print = netif_msg_link(fep);
-
-	mii_status = mii_full_status(mii);
-
-	if (!init_media && mii_status == fep->last_mii_status)
-		return;
-
-	fep->last_mii_status = mii_status;
-
-	link = !!(mii_status & MII_LINK);
-	duplex = !!(mii_status & MII_FULL);
-	speed = (mii_status & MII_100M) ? 100 : 10;
-
-	if (link == 0) {
-		netif_carrier_off(mii->dev);
-		netif_stop_queue(dev);
-		if (!init_media) {
-			spin_lock_irqsave(&fep->lock, flags);
-			(*fep->ops->stop)(dev);
-			spin_unlock_irqrestore(&fep->lock, flags);
-		}
-
-		if (ok_to_print)
-			printk(KERN_INFO "%s: link down\n", mii->dev->name);
-
-	} else {
-
-		mii->full_duplex = duplex;
-
-		netif_carrier_on(mii->dev);
-
-		spin_lock_irqsave(&fep->lock, flags);
-		fep->duplex = duplex;
-		fep->speed = speed;
-		(*fep->ops->restart)(dev);
-		spin_unlock_irqrestore(&fep->lock, flags);
-
-		netif_start_queue(dev);
-
-		if (ok_to_print)
-			printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n",
-			       dev->name, speed, duplex ? "full" : "half");
-	}
-}
-
-/**********************************************************************************/
-
-int fs_mii_read(struct net_device *dev, int phy_id, int location)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-	struct fs_enet_mii_bus *bus = fep->mii_bus;
-
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&bus->mii_lock, flags);
-	ret = (*bus->mii_read)(bus, phy_id, location);
-	spin_unlock_irqrestore(&bus->mii_lock, flags);
-
-	return ret;
-}
-
-void fs_mii_write(struct net_device *dev, int phy_id, int location, int value)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-	struct fs_enet_mii_bus *bus = fep->mii_bus;
-	unsigned long flags;
-
-	spin_lock_irqsave(&bus->mii_lock, flags);
-	(*bus->mii_write)(bus, phy_id, location, value);
-	spin_unlock_irqrestore(&bus->mii_lock, flags);
-}
-
-/*****************************************************************************/
-
-/* list of all registered mii buses */
-static LIST_HEAD(fs_mii_bus_list);
-
-static struct fs_enet_mii_bus *lookup_bus(int method, int id)
-{
-	struct list_head *ptr;
-	struct fs_enet_mii_bus *bus;
-
-	list_for_each(ptr, &fs_mii_bus_list) {
-		bus = list_entry(ptr, struct fs_enet_mii_bus, list);
-		if (bus->bus_info->method == method &&
-			bus->bus_info->id == id)
-			return bus;
-	}
-	return NULL;
-}
-
-static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)
-{
-	struct fs_enet_mii_bus *bus;
-	int ret = 0;
-
-	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
-	if (bus == NULL) {
-		ret = -ENOMEM;
-		goto err;
-	}
-	memset(bus, 0, sizeof(*bus));
-	spin_lock_init(&bus->mii_lock);
-	bus->bus_info = bi;
-	bus->refs = 0;
-	bus->usage_map = 0;
-
-	/* perform initialization */
-	switch (bi->method) {
-
-		case fsmii_fixed:
-			ret = fs_mii_fixed_init(bus);
-			if (ret != 0)
-				goto err;
-			break;
-
-		case fsmii_bitbang:
-			ret = fs_mii_bitbang_init(bus);
-			if (ret != 0)
-				goto err;
-			break;
-#ifdef CONFIG_FS_ENET_HAS_FEC
-		case fsmii_fec:
-			ret = fs_mii_fec_init(bus);
-			if (ret != 0)
-				goto err;
-			break;
-#endif
-		default:
-			ret = -EINVAL;
-			goto err;
-	}
-
-	list_add(&bus->list, &fs_mii_bus_list);
-
-	return bus;
-
-err:
-	if (bus)
-		kfree(bus);
-	return ERR_PTR(ret);
-}
-
-static void destroy_bus(struct fs_enet_mii_bus *bus)
-{
-	/* remove from bus list */
-	list_del(&bus->list);
-
-	/* nothing more needed */
-	kfree(bus);
-}
-
-int fs_mii_connect(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-	const struct fs_platform_info *fpi = fep->fpi;
-	struct fs_enet_mii_bus *bus = NULL;
-
-	/* check method validity */
-	switch (fpi->bus_info->method) {
-		case fsmii_fixed:
-		case fsmii_bitbang:
-			break;
-#ifdef CONFIG_FS_ENET_HAS_FEC
-		case fsmii_fec:
-			break;
-#endif
-		default:
-			printk(KERN_ERR DRV_MODULE_NAME
-			       ": %s Unknown MII bus method (%d)!\n",
-			       dev->name, fpi->bus_info->method);
-			return -EINVAL; 
-	}
-
-	bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id);
-
-	/* if not found create new bus */
-	if (bus == NULL) {
-		bus = create_bus(fpi->bus_info);
-		if (IS_ERR(bus)) {
-			printk(KERN_ERR DRV_MODULE_NAME
-			       ": %s MII bus creation failure!\n", dev->name);
-			return PTR_ERR(bus);
-		}
-	}
-
-	bus->refs++;
-
-	fep->mii_bus = bus;
-
-	fep->mii_if.dev = dev;
-	fep->mii_if.phy_id_mask = 0x1f;
-	fep->mii_if.reg_num_mask = 0x1f;
-	fep->mii_if.mdio_read = fs_mii_read;
-	fep->mii_if.mdio_write = fs_mii_write;
-	fep->mii_if.force_media = fpi->bus_info->disable_aneg;
-	fep->mii_if.phy_id = phy_id_detect(dev);
-
-	return 0;
-}
-
-void fs_mii_disconnect(struct net_device *dev)
-{
-	struct fs_enet_private *fep = netdev_priv(dev);
-	struct fs_enet_mii_bus *bus = NULL;
-
-	bus = fep->mii_bus;
-	fep->mii_bus = NULL;
-
-	if (--bus->refs <= 0)
-		destroy_bus(bus);
-}
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index e7ec96c..95022c0 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -5,6 +5,7 @@ #include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/phy.h>
 
 #include <linux/fs_enet_pd.h>
 
@@ -12,11 +13,29 @@ #include <asm/dma-mapping.h>
 
 #ifdef CONFIG_CPM1
 #include <asm/commproc.h>
+
+struct fec_info {
+        fec_t*  fecp;
+	u32     mii_speed;
+};
 #endif
 
 #ifdef CONFIG_CPM2
 #include <asm/cpm2.h>
 #endif
+
+/* This is used to operate with pins.
+  Note that the actual port size may
+    be different; cpm(s) handle it OK  */
+struct bb_info {
+	u8 mdio_dat_msk;
+	u8 mdio_dir_msk;
+	u8 *mdio_dir;
+	u8 *mdio_dat;
+	u8 mdc_msk;
+	u8 *mdc_dat;
+	int delay;
+};
 
 /* hw driver ops */
 struct fs_ops {
@@ -25,6 +44,7 @@ struct fs_ops {
 	void (*free_bd)(struct net_device *dev);
 	void (*cleanup_data)(struct net_device *dev);
 	void (*set_multicast_list)(struct net_device *dev);
+	void (*adjust_link)(struct net_device *dev);
 	void (*restart)(struct net_device *dev);
 	void (*stop)(struct net_device *dev);
 	void (*pre_request_irq)(struct net_device *dev, int irq);
@@ -99,10 +119,6 @@ struct fs_enet_mii_bus {
 		} fixed;
 	};
 };
-
-int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus);
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
-int fs_mii_fec_init(struct fs_enet_mii_bus *bus);
 
 struct fs_enet_private {
 	struct device *dev;	/* pointer back to the device (must be initialized first) */
@@ -130,7 +146,8 @@ struct fs_enet_private {
 	struct fs_enet_mii_bus *mii_bus;
 	int interrupt;
 
-	int duplex, speed;	/* current settings */
+	struct phy_device *phydev;
+	int oldduplex, oldspeed, oldlink;	/* current settings */
 
 	/* event masks */
 	u32 ev_napi_rx;		/* mask of NAPI rx events */
@@ -168,15 +185,9 @@ struct fs_enet_private {
 };
 
 /***************************************************************************/
-
-int fs_mii_read(struct net_device *dev, int phy_id, int location);
-void fs_mii_write(struct net_device *dev, int phy_id, int location, int value);
-
-void fs_mii_startup(struct net_device *dev);
-void fs_mii_shutdown(struct net_device *dev);
-void fs_mii_ack_int(struct net_device *dev);
-
-void fs_mii_link_status_change_check(struct net_device *dev, int init_media);
+int fs_enet_mdio_bb_init(void);
+int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
+int fs_enet_mdio_fec_init(void);
 
 void fs_init_bds(struct net_device *dev);
 void fs_cleanup_bds(struct net_device *dev);
@@ -194,7 +205,6 @@ int fs_enet_platform_init(void);
 void fs_enet_platform_cleanup(void);
 
 /***************************************************************************/
-
 /* buffer descriptor access macros */
 
 /* access macros */
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 95e2bb8..8bc711d 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -35,6 +35,7 @@ #include <linux/ethtool.h>
 #include <linux/bitops.h>
 #include <linux/fs.h>
 #include <linux/platform_device.h>
+#include <linux/phy.h>
 
 #include <asm/immap_cpm2.h>
 #include <asm/mpc8260.h>
@@ -123,20 +124,30 @@ static int do_pd_setup(struct fs_enet_pr
 
 	/* Attach the memory for the FCC Parameter RAM */
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
-	fep->fcc.ep = (void *)r->start;
-
+	fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1);
 	if (fep->fcc.ep == NULL)
 		return -EINVAL;
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");
-	fep->fcc.fccp = (void *)r->start;
-
+	fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1);
 	if (fep->fcc.fccp == NULL)
 		return -EINVAL;
+
+	if (fep->fpi->fcc_regs_c) {
 
-	fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
+		fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
+	} else {
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+				"fcc_regs_c");
+		fep->fcc.fcccp = (void *)ioremap(r->start,
+				r->end - r->start + 1);
+	}
 
 	if (fep->fcc.fcccp == NULL)
+		return -EINVAL;
+
+	fep->fcc.mem = (void *)fep->fpi->mem_offset;
+	if (fep->fcc.mem == NULL)
 		return -EINVAL;
 
 	return 0;
@@ -156,8 +167,6 @@ static int setup_data(struct net_device 
 	if ((unsigned int)fep->fcc.idx >= 3)	/* max 3 FCCs */
 		return -EINVAL;
 
-	fep->fcc.mem = (void *)fpi->mem_offset;
-
 	if (do_pd_setup(fep) != 0)
 		return -EINVAL;
 
@@ -395,7 +404,7 @@ static void restart(struct net_device *d
 
 	/* adjust to speed (for RMII mode) */
 	if (fpi->use_rmii) {
-		if (fep->speed == 100)
+		if (fep->phydev->speed == 100)
 			C8(fcccp, fcc_gfemr, 0x20);
 		else
 			S8(fcccp, fcc_gfemr, 0x20);
@@ -421,7 +430,7 @@ static void restart(struct net_device *d
 		S32(fccp, fcc_fpsmr, FCC_PSMR_RMII);
 
 	/* adjust to duplex mode */
-	if (fep->duplex)
+	if (fep->phydev->duplex)
 		S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
 	else
 		C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
@@ -487,7 +496,10 @@ static void rx_bd_done(struct net_device
 
 static void tx_kickstart(struct net_device *dev)
 {
-	/* nothing */
+	struct fs_enet_private *fep = netdev_priv(dev);
+	fcc_t *fccp = fep->fcc.fccp;
+
+	S32(fccp, fcc_ftodr, 0x80);
 }
 
 static u32 get_int_events(struct net_device *dev)
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 3dad69d..99678c3 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -47,6 +47,7 @@ #include <asm/commproc.h>
 #endif
 
 #include "fs_enet.h"
+#include "fec.h"
 
 /*************************************************/
 
@@ -76,48 +77,6 @@ #define FS(_fecp, _reg, _v) FW(_fecp, _r
 /* clear bits */
 #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v))
 
-
-/* CRC polynomium used by the FEC for the multicast group filtering */
-#define FEC_CRC_POLY   0x04C11DB7
-
-#define FEC_MAX_MULTICAST_ADDRS	64
-
-/* Interrupt events/masks.
-*/
-#define FEC_ENET_HBERR	0x80000000U	/* Heartbeat error          */
-#define FEC_ENET_BABR	0x40000000U	/* Babbling receiver        */
-#define FEC_ENET_BABT	0x20000000U	/* Babbling transmitter     */
-#define FEC_ENET_GRA	0x10000000U	/* Graceful stop complete   */
-#define FEC_ENET_TXF	0x08000000U	/* Full frame transmitted   */
-#define FEC_ENET_TXB	0x04000000U	/* A buffer was transmitted */
-#define FEC_ENET_RXF	0x02000000U	/* Full frame received      */
-#define FEC_ENET_RXB	0x01000000U	/* A buffer was received    */
-#define FEC_ENET_MII	0x00800000U	/* MII interrupt            */
-#define FEC_ENET_EBERR	0x00400000U	/* SDMA bus error           */
-
-#define FEC_ECNTRL_PINMUX	0x00000004
-#define FEC_ECNTRL_ETHER_EN	0x00000002
-#define FEC_ECNTRL_RESET	0x00000001
-
-#define FEC_RCNTRL_BC_REJ	0x00000010
-#define FEC_RCNTRL_PROM		0x00000008
-#define FEC_RCNTRL_MII_MODE	0x00000004
-#define FEC_RCNTRL_DRT		0x00000002
-#define FEC_RCNTRL_LOOP		0x00000001
-
-#define FEC_TCNTRL_FDEN		0x00000004
-#define FEC_TCNTRL_HBC		0x00000002
-#define FEC_TCNTRL_GTS		0x00000001
-
-
-/* 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
-
-#define FEC_MII_LOOPS	10000
-
 /*
  * Delay to wait for FEC reset command to complete (in us) 
  */
@@ -303,12 +262,14 @@ #endif
 	dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
 	int r;
 	u32 addrhi, addrlo;
+
+	struct mii_bus* mii = fep->phydev->bus;
+	struct fec_info* fec_inf = mii->priv;
 
 	r = whack_reset(fep->fec.fecp);
 	if (r != 0)
 		printk(KERN_ERR DRV_MODULE_NAME
 				": %s FEC Reset FAILED!\n", dev->name);
-
 	/*
 	 * Set station address. 
 	 */
@@ -353,7 +314,7 @@ #endif
 	/*
 	 * Set MII speed. 
 	 */
-	FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed);
+	FW(fecp, mii_speed, fec_inf->mii_speed);
 
 	/*
 	 * Clear any outstanding interrupt. 
@@ -391,11 +352,12 @@ #ifdef CONFIG_DUET
 	}
 #endif
 
+
 	FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
 	/*
 	 * adjust to duplex mode 
 	 */
-	if (fep->duplex) {
+	if (fep->phydev->duplex) {
 		FC(fecp, r_cntrl, FEC_RCNTRL_DRT);
 		FS(fecp, x_cntrl, FEC_TCNTRL_FDEN);	/* FD enable */
 	} else {
@@ -419,9 +381,11 @@ #endif
 static void stop(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
+	const struct fs_platform_info *fpi = fep->fpi;
 	fec_t *fecp = fep->fec.fecp;
-	struct fs_enet_mii_bus *bus = fep->mii_bus;
-	const struct fs_mii_bus_info *bi = bus->bus_info;
+
+	struct fec_info* feci= fep->phydev->bus->priv;
+
 	int i;
 
 	if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0)
@@ -445,11 +409,11 @@ static void stop(struct net_device *dev)
 	fs_cleanup_bds(dev);
 
 	/* shut down FEC1? that's where the mii bus is */
-	if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) {
+	if (fpi->has_phy) {
 		FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
 		FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
 		FW(fecp, ievent, FEC_ENET_MII);
-		FW(fecp, mii_speed, bus->fec.mii_speed);
+		FW(fecp, mii_speed, feci->mii_speed);
 	}
 }
 
@@ -583,74 +547,4 @@ const struct fs_ops fs_fec_ops = {
 	.allocate_bd		= allocate_bd,
 	.free_bd		= free_bd,
 };
-
-/***********************************************************************/
-
-static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
-{
-	fec_t *fecp = bus->fec.fecp;
-	int i, ret = -1;
-
-	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
-		BUG();
-
-	/* Add PHY address to register command.  */
-	FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));
 
-	for (i = 0; i < FEC_MII_LOOPS; i++)
-		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
-			break;
-
-	if (i < FEC_MII_LOOPS) {
-		FW(fecp, ievent, FEC_ENET_MII);
-		ret = FR(fecp, mii_data) & 0xffff;
-	}
-
-	return ret;
-}
-
-static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value)
-{
-	fec_t *fecp = bus->fec.fecp;
-	int i;
-
-	/* this must never happen */
-	if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
-		BUG();
-
-	/* Add PHY address to register command.  */
-	FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));
-
-	for (i = 0; i < FEC_MII_LOOPS; i++)
-		if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
-			break;
-
-	if (i < FEC_MII_LOOPS)
-		FW(fecp, ievent, FEC_ENET_MII);
-}
-
-int fs_mii_fec_init(struct fs_enet_mii_bus *bus)
-{
-	bd_t *bd = (bd_t *)__res;
-	const struct fs_mii_bus_info *bi = bus->bus_info;
-	fec_t *fecp;
-
-	if (bi->id != 0)
-		return -1;
-
-	bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec;
-	bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2)
-				& 0x3F) << 1;
-
-	fecp = bus->fec.fecp;
-
-	FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
-	FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
-	FW(fecp, ievent, FEC_ENET_MII);
-	FW(fecp, mii_speed, bus->fec.mii_speed);
-
-	bus->mii_read = mii_read;
-	bus->mii_write = mii_write;
-
-	return 0;
-}
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index a772b28..d829120 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -370,7 +370,7 @@ static void restart(struct net_device *d
 	W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22);
 
 	/* Set full duplex mode if needed */
-	if (fep->duplex)
+	if (fep->phydev->duplex)
 		S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE);
 
 	S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
@@ -500,6 +500,8 @@ static void tx_restart(struct net_device
 
 	scc_cr_cmd(fep, CPM_CR_RESTART_TX);
 }
+
+
 
 /*************************************************************************/
 
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 24a5e2e..cf2955f 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -34,6 +34,7 @@ #include <linux/spinlock.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/platform_device.h>
 
 #include <asm/pgtable.h>
 #include <asm/irq.h>
@@ -41,129 +42,25 @@ #include <asm/uaccess.h>
 
 #include "fs_enet.h"
 
-#ifdef CONFIG_8xx
-static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
+static int bitbang_prep_bit(u8 **datp, u8 *mskp,
+		struct fs_mii_bit *mii_bit)
 {
-	immap_t *im = (immap_t *)fs_enet_immap;
-	void *dir, *dat, *ppar;
+	void *dat;
 	int adv;
 	u8 msk;
-
-	switch (port) {
-		case fsiop_porta:
-			dir = &im->im_ioport.iop_padir;
-			dat = &im->im_ioport.iop_padat;
-			ppar = &im->im_ioport.iop_papar;
-			break;
-
-		case fsiop_portb:
-			dir = &im->im_cpm.cp_pbdir;
-			dat = &im->im_cpm.cp_pbdat;
-			ppar = &im->im_cpm.cp_pbpar;
-			break;
-
-		case fsiop_portc:
-			dir = &im->im_ioport.iop_pcdir;
-			dat = &im->im_ioport.iop_pcdat;
-			ppar = &im->im_ioport.iop_pcpar;
-			break;
-
-		case fsiop_portd:
-			dir = &im->im_ioport.iop_pddir;
-			dat = &im->im_ioport.iop_pddat;
-			ppar = &im->im_ioport.iop_pdpar;
-			break;
-
-		case fsiop_porte:
-			dir = &im->im_cpm.cp_pedir;
-			dat = &im->im_cpm.cp_pedat;
-			ppar = &im->im_cpm.cp_pepar;
-			break;
-
-		default:
-			printk(KERN_ERR DRV_MODULE_NAME
-			       "Illegal port value %d!\n", port);
-			return -EINVAL;
-	}
-
-	adv = bit >> 3;
-	dir = (char *)dir + adv;
-	dat = (char *)dat + adv;
-	ppar = (char *)ppar + adv;
-
-	msk = 1 << (7 - (bit & 7));
-	if ((in_8(ppar) & msk) != 0) {
-		printk(KERN_ERR DRV_MODULE_NAME
-		       "pin %d on port %d is not general purpose!\n", bit, port);
-		return -EINVAL;
-	}
 
-	*dirp = dir;
-	*datp = dat;
-	*mskp = msk;
+	dat = (void*) mii_bit->offset;
 
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_8260
-static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
-{
-	iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport;
-	void *dir, *dat, *ppar;
-	int adv;
-	u8 msk;
-
-	switch (port) {
-		case fsiop_porta:
-			dir = &io->iop_pdira;
-			dat = &io->iop_pdata;
-			ppar = &io->iop_ppara;
-			break;
-
-		case fsiop_portb:
-			dir = &io->iop_pdirb;
-			dat = &io->iop_pdatb;
-			ppar = &io->iop_pparb;
-			break;
-
-		case fsiop_portc:
-			dir = &io->iop_pdirc;
-			dat = &io->iop_pdatc;
-			ppar = &io->iop_pparc;
-			break;
-
-		case fsiop_portd:
-			dir = &io->iop_pdird;
-			dat = &io->iop_pdatd;
-			ppar = &io->iop_ppard;
-			break;
-
-		default:
-			printk(KERN_ERR DRV_MODULE_NAME
-			       "Illegal port value %d!\n", port);
-			return -EINVAL;
-	}
-
-	adv = bit >> 3;
-	dir = (char *)dir + adv;
+	adv = mii_bit->bit >> 3;
 	dat = (char *)dat + adv;
-	ppar = (char *)ppar + adv;
-
-	msk = 1 << (7 - (bit & 7));
-	if ((in_8(ppar) & msk) != 0) {
-		printk(KERN_ERR DRV_MODULE_NAME
-		       "pin %d on port %d is not general purpose!\n", bit, port);
-		return -EINVAL;
-	}
 
-	*dirp = dir;
+	msk = 1 << (7 - (mii_bit->bit & 7));
+
 	*datp = dat;
 	*mskp = msk;
 
 	return 0;
 }
-#endif
 
 static inline void bb_set(u8 *p, u8 m)
 {
@@ -180,44 +77,44 @@ static inline int bb_read(u8 *p, u8 m)
 	return (in_8(p) & m) != 0;
 }
 
-static inline void mdio_active(struct fs_enet_mii_bus *bus)
+static inline void mdio_active(struct bb_info *bitbang)
 {
-	bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);
+	bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk);
 }
 
-static inline void mdio_tristate(struct fs_enet_mii_bus *bus)
+static inline void mdio_tristate(struct bb_info *bitbang )
 {
-	bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);
+	bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk);
 }
 
-static inline int mdio_read(struct fs_enet_mii_bus *bus)
+static inline int mdio_read(struct bb_info *bitbang )
 {
-	return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+	return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk);
 }
 
-static inline void mdio(struct fs_enet_mii_bus *bus, int what)
+static inline void mdio(struct bb_info *bitbang , int what)
 {
 	if (what)
-		bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+		bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk);
 	else
-		bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+		bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk);
 }
 
-static inline void mdc(struct fs_enet_mii_bus *bus, int what)
+static inline void mdc(struct bb_info *bitbang , int what)
 {
 	if (what)
-		bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);
+		bb_set(bitbang->mdc_dat, bitbang->mdc_msk);
 	else
-		bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);
+		bb_clr(bitbang->mdc_dat, bitbang->mdc_msk);
 }
 
-static inline void mii_delay(struct fs_enet_mii_bus *bus)
+static inline void mii_delay(struct bb_info *bitbang )
 {
-	udelay(bus->bus_info->i.bitbang.delay);
+	udelay(bitbang->delay);
 }
 
 /* Utility to send the preamble, address, and register (common to read and write). */
-static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg)
+static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg)
 {
 	int j;
 
@@ -229,177 +126,284 @@ static void bitbang_pre(struct fs_enet_m
 	 * but it is safer and will be much more robust.
 	 */
 
-	mdio_active(bus);
-	mdio(bus, 1);
+	mdio_active(bitbang);
+	mdio(bitbang, 1);
 	for (j = 0; j < 32; j++) {
-		mdc(bus, 0);
-		mii_delay(bus);
-		mdc(bus, 1);
-		mii_delay(bus);
+		mdc(bitbang, 0);
+		mii_delay(bitbang);
+		mdc(bitbang, 1);
+		mii_delay(bitbang);
 	}
 
 	/* send the start bit (01) and the read opcode (10) or write (10) */
-	mdc(bus, 0);
-	mdio(bus, 0);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
-	mdc(bus, 0);
-	mdio(bus, 1);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
-	mdc(bus, 0);
-	mdio(bus, read);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
-	mdc(bus, 0);
-	mdio(bus, !read);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
-
+	mdc(bitbang, 0);
+	mdio(bitbang, 0);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+	mdc(bitbang, 0);
+	mdio(bitbang, 1);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+	mdc(bitbang, 0);
+	mdio(bitbang, read);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+	mdc(bitbang, 0);
+	mdio(bitbang, !read);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+
 	/* send the PHY address */
-	for (j = 0; j < 5; j++) {
-		mdc(bus, 0);
-		mdio(bus, (addr & 0x10) != 0);
-		mii_delay(bus);
-		mdc(bus, 1);
-		mii_delay(bus);
+	for (j = 0; j < 5; j++) {
+		mdc(bitbang, 0);
+		mdio(bitbang, (addr & 0x10) != 0);
+		mii_delay(bitbang);
+		mdc(bitbang, 1);
+		mii_delay(bitbang);
 		addr <<= 1;
 	}
 
 	/* send the register address */
-	for (j = 0; j < 5; j++) {
-		mdc(bus, 0);
-		mdio(bus, (reg & 0x10) != 0);
-		mii_delay(bus);
-		mdc(bus, 1);
-		mii_delay(bus);
+	for (j = 0; j < 5; j++) {
+		mdc(bitbang, 0);
+		mdio(bitbang, (reg & 0x10) != 0);
+		mii_delay(bitbang);
+		mdc(bitbang, 1);
+		mii_delay(bitbang);
 		reg <<= 1;
 	}
 }
 
-static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
+static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location)
 {
 	u16 rdreg;
 	int ret, j;
 	u8 addr = phy_id & 0xff;
 	u8 reg = location & 0xff;
+	struct bb_info* bitbang = bus->priv;
 
-	bitbang_pre(bus, 1, addr, reg);
+	bitbang_pre(bitbang, 1, addr, reg);
 
 	/* tri-state our MDIO I/O pin so we can read */
-	mdc(bus, 0);
-	mdio_tristate(bus);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
-
+	mdc(bitbang, 0);
+	mdio_tristate(bitbang);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+
 	/* check the turnaround bit: the PHY should be driving it to zero */
-	if (mdio_read(bus) != 0) {
+	if (mdio_read(bitbang) != 0) {
 		/* PHY didn't drive TA low */
 		for (j = 0; j < 32; j++) {
-			mdc(bus, 0);
-			mii_delay(bus);
-			mdc(bus, 1);
-			mii_delay(bus);
+			mdc(bitbang, 0);
+			mii_delay(bitbang);
+			mdc(bitbang, 1);
+			mii_delay(bitbang);
 		}
 		ret = -1;
 		goto out;
 	}
 
-	mdc(bus, 0);
-	mii_delay(bus);
+	mdc(bitbang, 0);
+	mii_delay(bitbang);
 
 	/* read 16 bits of register data, MSB first */
 	rdreg = 0;
 	for (j = 0; j < 16; j++) {
-		mdc(bus, 1);
-		mii_delay(bus);
+		mdc(bitbang, 1);
+		mii_delay(bitbang);
 		rdreg <<= 1;
-		rdreg |= mdio_read(bus);
-		mdc(bus, 0);
-		mii_delay(bus);
+		rdreg |= mdio_read(bitbang);
+		mdc(bitbang, 0);
+		mii_delay(bitbang);
 	}
 
-	mdc(bus, 1);
-	mii_delay(bus);
-	mdc(bus, 0);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+	mdc(bitbang, 0);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
 
 	ret = rdreg;
 out:
 	return ret;
 }
 
-static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)
+static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val)
 {
 	int j;
+	struct bb_info* bitbang = bus->priv;
+
 	u8 addr = phy_id & 0xff;
 	u8 reg = location & 0xff;
 	u16 value = val & 0xffff;
 
-	bitbang_pre(bus, 0, addr, reg);
+	bitbang_pre(bitbang, 0, addr, reg);
 
 	/* send the turnaround (10) */
-	mdc(bus, 0);
-	mdio(bus, 1);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
-	mdc(bus, 0);
-	mdio(bus, 0);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
-
+	mdc(bitbang, 0);
+	mdio(bitbang, 1);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+	mdc(bitbang, 0);
+	mdio(bitbang, 0);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+
 	/* write 16 bits of register data, MSB first */
-	for (j = 0; j < 16; j++) {
-		mdc(bus, 0);
-		mdio(bus, (value & 0x8000) != 0);
-		mii_delay(bus);
-		mdc(bus, 1);
-		mii_delay(bus);
+	for (j = 0; j < 16; j++) {
+		mdc(bitbang, 0);
+		mdio(bitbang, (value & 0x8000) != 0);
+		mii_delay(bitbang);
+		mdc(bitbang, 1);
+		mii_delay(bitbang);
 		value <<= 1;
 	}
 
 	/*
 	 * Tri-state the MDIO line.
 	 */
-	mdio_tristate(bus);
-	mdc(bus, 0);
-	mii_delay(bus);
-	mdc(bus, 1);
-	mii_delay(bus);
+	mdio_tristate(bitbang);
+	mdc(bitbang, 0);
+	mii_delay(bitbang);
+	mdc(bitbang, 1);
+	mii_delay(bitbang);
+	return 0;
 }
 
-int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus)
+static int fs_enet_mii_bb_reset(struct mii_bus *bus)
 {
-	const struct fs_mii_bus_info *bi = bus->bus_info;
+	/*nothing here - dunno how to reset it*/
+	return 0;
+}
+
+static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi)
+{
 	int r;
+
+	bitbang->delay = fmpi->delay;
 
-	r = bitbang_prep_bit(&bus->bitbang.mdio_dir,
-			 &bus->bitbang.mdio_dat,
-			 &bus->bitbang.mdio_msk,
-			 bi->i.bitbang.mdio_port,
-			 bi->i.bitbang.mdio_bit);
+	r = bitbang_prep_bit(&bitbang->mdio_dir,
+			 &bitbang->mdio_dir_msk,
+			 &fmpi->mdio_dir);
 	if (r != 0)
 		return r;
 
-	r = bitbang_prep_bit(&bus->bitbang.mdc_dir,
-			 &bus->bitbang.mdc_dat,
-			 &bus->bitbang.mdc_msk,
-			 bi->i.bitbang.mdc_port,
-			 bi->i.bitbang.mdc_bit);
+	r = bitbang_prep_bit(&bitbang->mdio_dat,
+			 &bitbang->mdio_dat_msk,
+			 &fmpi->mdio_dat);
 	if (r != 0)
 		return r;
 
-	bus->mii_read = mii_read;
-	bus->mii_write = mii_write;
+	r = bitbang_prep_bit(&bitbang->mdc_dat,
+			 &bitbang->mdc_msk,
+			 &fmpi->mdc_dat);
+	if (r != 0)
+		return r;
 
 	return 0;
 }
+
+
+static int __devinit fs_enet_mdio_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct fs_mii_bb_platform_info *pdata;
+	struct mii_bus *new_bus;
+	struct bb_info *bitbang;
+	int err = 0;
+
+	if (NULL == dev)
+		return -EINVAL;
+
+	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+	if (NULL == new_bus)
+		return -ENOMEM;
+
+	bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+
+	if (NULL == bitbang)
+		return -ENOMEM;
+
+	new_bus->name = "BB MII Bus",
+	new_bus->read = &fs_enet_mii_bb_read,
+	new_bus->write = &fs_enet_mii_bb_write,
+	new_bus->reset = &fs_enet_mii_bb_reset,
+	new_bus->id = pdev->id;
+
+	new_bus->phy_mask = ~0x9;
+	pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data;
+
+	if (NULL == pdata) {
+		printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id);
+		return -ENODEV;
+	}
+
+	/*set up workspace*/
+	fs_mii_bitbang_init(bitbang, pdata);
+
+	new_bus->priv = bitbang;
+
+	new_bus->irq = pdata->irq;
+
+	new_bus->dev = dev;
+	dev_set_drvdata(dev, new_bus);
+
+	err = mdiobus_register(new_bus);
+
+	if (0 != err) {
+		printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+				new_bus->name);
+		goto bus_register_fail;
+	}
+
+	return 0;
+
+bus_register_fail:
+	kfree(bitbang);
+	kfree(new_bus);
+
+	return err;
+}
+
+
+static int fs_enet_mdio_remove(struct device *dev)
+{
+	struct mii_bus *bus = dev_get_drvdata(dev);
+
+	mdiobus_unregister(bus);
+
+	dev_set_drvdata(dev, NULL);
+
+	iounmap((void *) (&bus->priv));
+	bus->priv = NULL;
+	kfree(bus);
+
+	return 0;
+}
+
+static struct device_driver fs_enet_bb_mdio_driver = {
+	.name = "fsl-bb-mdio",
+	.bus = &platform_bus_type,
+	.probe = fs_enet_mdio_probe,
+	.remove = fs_enet_mdio_remove,
+};
+
+int fs_enet_mdio_bb_init(void)
+{
+	return driver_register(&fs_enet_bb_mdio_driver);
+}
+
+void fs_enet_mdio_bb_exit(void)
+{
+	driver_unregister(&fs_enet_bb_mdio_driver);
+}
+
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
new file mode 100644
index 0000000..1328e10
--- /dev/null
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -0,0 +1,243 @@
+/*
+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 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.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+#include "fec.h"
+
+/* 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
+
+#define FEC_MII_LOOPS	10000
+
+static int match_has_phy (struct device *dev, void* data)
+{
+	struct platform_device* pdev = container_of(dev, struct platform_device, dev);
+	struct fs_platform_info* fpi;
+	if(strcmp(pdev->name, (char*)data))
+	{
+	    return 0;
+	}
+
+	fpi = pdev->dev.platform_data;
+	if((fpi)&&(fpi->has_phy))
+		return 1;
+	return 0;
+}
+
+static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi)
+{
+	struct resource *r;
+	fec_t *fecp;
+	char* name = "fsl-cpm-fec";
+
+	/* we need fec in order to be useful */
+	struct platform_device *fec_pdev =
+		container_of(bus_find_device(&platform_bus_type, NULL, name, match_has_phy),
+				struct platform_device, dev);
+
+	if(fec_pdev == NULL) {
+		printk(KERN_ERR"Unable to find PHY for %s", name);
+		return -ENODEV;
+	}
+
+	r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs");
+
+	fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t));
+	fec->mii_speed = fmpi->mii_speed;
+
+	setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
+	setbits32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
+	out_be32(&fecp->fec_ievent, FEC_ENET_MII);
+	out_be32(&fecp->fec_mii_speed, fec->mii_speed);
+
+	return 0;
+}
+
+static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
+{
+	struct fec_info* fec = bus->priv;
+	fec_t *fecp = fec->fecp;
+	int i, ret = -1;
+
+	if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+		BUG();
+
+	/* Add PHY address to register command.  */
+	out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location));
+
+	for (i = 0; i < FEC_MII_LOOPS; i++)
+		if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0)
+			break;
+
+	if (i < FEC_MII_LOOPS) {
+		out_be32(&fecp->fec_ievent, FEC_ENET_MII);
+		ret = in_be32(&fecp->fec_mii_data) & 0xffff;
+	}
+
+	return ret;
+
+}
+
+static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+{
+	struct fec_info* fec = bus->priv;
+	fec_t *fecp = fec->fecp;
+	int i;
+
+	/* this must never happen */
+	if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+		BUG();
+
+	/* Add PHY address to register command.  */
+	out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val));
+
+	for (i = 0; i < FEC_MII_LOOPS; i++)
+		if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0)
+			break;
+
+	if (i < FEC_MII_LOOPS)
+		out_be32(&fecp->fec_ievent, FEC_ENET_MII);
+
+	return 0;
+
+}
+
+static int fs_enet_fec_mii_reset(struct mii_bus *bus)
+{
+	/* nothing here - for now */
+	return 0;
+}
+
+static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct fs_mii_fec_platform_info *pdata;
+	struct mii_bus *new_bus;
+	struct fec_info *fec;
+	int err = 0;
+	if (NULL == dev)
+		return -EINVAL;
+	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+	if (NULL == new_bus)
+		return -ENOMEM;
+
+	fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
+
+	if (NULL == fec)
+		return -ENOMEM;
+
+	new_bus->name = "FEC MII Bus",
+	new_bus->read = &fs_enet_fec_mii_read,
+	new_bus->write = &fs_enet_fec_mii_write,
+	new_bus->reset = &fs_enet_fec_mii_reset,
+	new_bus->id = pdev->id;
+
+	pdata = (struct fs_mii_fec_platform_info *)pdev->dev.platform_data;
+
+	if (NULL == pdata) {
+		printk(KERN_ERR "fs_enet FEC mdio %d: Missing platform data!\n", pdev->id);
+		return -ENODEV;
+	}
+
+	/*set up workspace*/
+
+	fs_mii_fec_init(fec, pdata);
+	new_bus->priv = fec;
+
+	new_bus->irq = pdata->irq;
+
+	new_bus->dev = dev;
+	dev_set_drvdata(dev, new_bus);
+
+	err = mdiobus_register(new_bus);
+
+	if (0 != err) {
+		printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+				new_bus->name);
+		goto bus_register_fail;
+	}
+
+	return 0;
+
+bus_register_fail:
+	kfree(new_bus);
+
+	return err;
+}
+
+
+static int fs_enet_fec_mdio_remove(struct device *dev)
+{
+	struct mii_bus *bus = dev_get_drvdata(dev);
+
+	mdiobus_unregister(bus);
+
+	dev_set_drvdata(dev, NULL);
+	kfree(bus->priv);
+
+	bus->priv = NULL;
+	kfree(bus);
+
+	return 0;
+}
+
+static struct device_driver fs_enet_fec_mdio_driver = {
+	.name = "fsl-cpm-fec-mdio",
+	.bus = &platform_bus_type,
+	.probe = fs_enet_fec_mdio_probe,
+	.remove = fs_enet_fec_mdio_remove,
+};
+
+int fs_enet_mdio_fec_init(void)
+{
+	return driver_register(&fs_enet_fec_mdio_driver);
+}
+
+void fs_enet_mdio_fec_exit(void)
+{
+	driver_unregister(&fs_enet_fec_mdio_driver);
+}
+
diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c
deleted file mode 100644
index b3e192d..0000000
--- a/drivers/net/fs_enet/mii-fixed.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
- *
- * Copyright (c) 2003 Intracom S.A. 
- *  by Pantelis Antoniou <panto@intracom.gr>
- * 
- * 2005 (c) MontaVista Software, Inc. 
- * Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * 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.
- */
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "fs_enet.h"
-
-static const u16 mii_regs[7] = {
-	0x3100,
-	0x786d,
-	0x0fff,
-	0x0fff,
-	0x01e1,
-	0x45e1,
-	0x0003,
-};
-
-static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
-{
-	int ret = 0;
-
-	if ((unsigned int)location >= ARRAY_SIZE(mii_regs))
-		return -1;
-
-	if (location != 5)
-		ret = mii_regs[location];
-	else
-		ret = bus->fixed.lpa;
-
-	return ret;
-}
-
-static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)
-{
-	/* do nothing */
-}
-
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus)
-{
-	const struct fs_mii_bus_info *bi = bus->bus_info;
-
-	bus->fixed.lpa = 0x45e1;	/* default 100Mb, full duplex */
-
-	/* if speed is fixed at 10Mb, remove 100Mb modes */
-	if (bi->i.fixed.speed == 10)
-		bus->fixed.lpa &= ~LPA_100;
-
-	/* if duplex is half, remove full duplex modes */
-	if (bi->i.fixed.duplex == 0)
-		bus->fixed.lpa &= ~LPA_DUPLEX;
-
-	bus->mii_read = mii_read;
-	bus->mii_write = mii_write;
-
-	return 0;
-}

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/6] FS_ENET: use PAL for mii management (BSP part)
       [not found] <20060623231648.6721.3495.stgit@localhost.localdomain>
  2006-06-23 23:16 ` [PATCH 1/6] PAL: Support of the fixed PHY Vitaly Bordug
  2006-06-23 23:16 ` [PATCH 2/6] FS_ENET: Utilize Phy abstraction Vitaly Bordug
@ 2006-06-23 23:17 ` Vitaly Bordug
  2006-06-23 23:17 ` [PATCH 4/6] FS_ENET: phydev pointer may be dereferenced without NULL check Vitaly Bordug
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-23 23:17 UTC (permalink / raw)
  To: linuxppc-dev


This patch should update the board-specific parts of fs_enet infrastructure to utilize
Phy Abstraction Layer subsystem. Inside there are portions to respect driver changes for 
8272ads, 885ads, 866ads, and 8560ads.

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
---

 arch/ppc/platforms/85xx/mpc8560_ads.c        |   89 ++++++++++++
 arch/ppc/platforms/85xx/mpc85xx_ads_common.h |   19 +++
 arch/ppc/platforms/mpc8272ads_setup.c        |  162 ++++++++++++----------
 arch/ppc/platforms/mpc866ads_setup.c         |  192 +++++++++++++-------------
 arch/ppc/platforms/mpc885ads_setup.c         |  177 +++++++++---------------
 arch/ppc/platforms/pq2ads_pd.h               |   82 -----------
 arch/ppc/syslib/mpc85xx_devices.c            |   89 ++++++++++++
 arch/ppc/syslib/mpc8xx_devices.c             |    8 +
 arch/ppc/syslib/mpc8xx_sys.c                 |    6 +
 arch/ppc/syslib/pq2_devices.c                |    5 +
 arch/ppc/syslib/pq2_sys.c                    |    3 
 include/asm-ppc/cpm2.h                       |   95 +++++++++++++
 include/asm-ppc/mpc8260.h                    |    1 
 include/asm-ppc/mpc8xx.h                     |    1 
 include/linux/fs_enet_pd.h                   |   54 +++----
 15 files changed, 585 insertions(+), 398 deletions(-)

diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
index 0cb2e86..92c46d8 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -30,6 +30,7 @@ #include <linux/serial_core.h>
 #include <linux/initrd.h>
 #include <linux/module.h>
 #include <linux/fsl_devices.h>
+#include <linux/fs_enet_pd.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -59,6 +60,71 @@ #include <syslib/ppc85xx_setup.h>
  * Setup the architecture
  *
  */
+static void init_fcc_ioports(void)
+{
+	struct immap *immap;
+	struct io_port *io;
+	u32 tempval;
+
+	immap = cpm2_immr;
+
+	io = &immap->im_ioport;
+	/* FCC2/3 are on the ports B/C. */
+	tempval = in_be32(&io->iop_pdirb);
+	tempval &= ~PB2_DIRB0;
+	tempval |= PB2_DIRB1;
+	out_be32(&io->iop_pdirb, tempval);
+
+	tempval = in_be32(&io->iop_psorb);
+	tempval &= ~PB2_PSORB0;
+	tempval |= PB2_PSORB1;
+	out_be32(&io->iop_psorb, tempval);
+
+	tempval = in_be32(&io->iop_pparb);
+	tempval |= (PB2_DIRB0 | PB2_DIRB1);
+	out_be32(&io->iop_pparb, tempval);
+
+	tempval = in_be32(&io->iop_pdirb);
+	tempval &= ~PB3_DIRB0;
+	tempval |= PB3_DIRB1;
+	out_be32(&io->iop_pdirb, tempval);
+
+	tempval = in_be32(&io->iop_psorb);
+	tempval &= ~PB3_PSORB0;
+	tempval |= PB3_PSORB1;
+	out_be32(&io->iop_psorb, tempval);
+
+	tempval = in_be32(&io->iop_pparb);
+	tempval |= (PB3_DIRB0 | PB3_DIRB1);
+	out_be32(&io->iop_pparb, tempval);
+
+        tempval = in_be32(&io->iop_pdirc);
+        tempval |= PC3_DIRC1;
+        out_be32(&io->iop_pdirc, tempval);
+
+        tempval = in_be32(&io->iop_pparc);
+        tempval |= PC3_DIRC1;
+        out_be32(&io->iop_pparc, tempval);
+
+	/* Port C has clocks......  */
+	tempval = in_be32(&io->iop_psorc);
+	tempval &= ~(CLK_TRX);
+	out_be32(&io->iop_psorc, tempval);
+
+	tempval = in_be32(&io->iop_pdirc);
+	tempval &= ~(CLK_TRX);
+	out_be32(&io->iop_pdirc, tempval);
+	tempval = in_be32(&io->iop_pparc);
+	tempval |= (CLK_TRX);
+	out_be32(&io->iop_pparc, tempval);
+
+	/* Configure Serial Interface clock routing.
+	 * First,  clear all FCC bits to zero,
+	 * then set the ones we want.
+	 */
+	immap->im_cpmux.cmx_fcr &= ~(CPMUX_CLK_MASK);
+	immap->im_cpmux.cmx_fcr |= CPMUX_CLK_ROUTE;
+}
 
 static void __init
 mpc8560ads_setup_arch(void)
@@ -67,6 +133,7 @@ mpc8560ads_setup_arch(void)
 	unsigned int freq;
 	struct gianfar_platform_data *pdata;
 	struct gianfar_mdio_data *mdata;
+	struct fs_platform_info *fpi;
 
 	cpm2_reset();
 
@@ -109,6 +176,28 @@ #endif
 		pdata->bus_id = 0;
 		pdata->phy_id = 1;
 		memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+	}
+
+	init_fcc_ioports();
+	ppc_sys_device_remove(MPC85xx_CPM_FCC1);
+
+	fpi = (struct fs_platform_info *) ppc_sys_get_pdata(MPC85xx_CPM_FCC2);
+	if (fpi) {
+		memcpy(fpi->macaddr, binfo->bi_enet2addr, 6);
+		fpi->bus_id = "0:02";
+		fpi->phy_addr = 2;
+		fpi->dpram_offset = (u32)cpm2_immr->im_dprambase;
+		fpi->fcc_regs_c = (u32)&cpm2_immr->im_fcc_c[1];
+	}
+
+	fpi = (struct fs_platform_info *) ppc_sys_get_pdata(MPC85xx_CPM_FCC3);
+	if (fpi) {
+		memcpy(fpi->macaddr, binfo->bi_enet2addr, 6);
+		fpi->macaddr[5] += 1;
+		fpi->bus_id = "0:03";
+		fpi->phy_addr = 3;
+		fpi->dpram_offset = (u32)cpm2_immr->im_dprambase;
+		fpi->fcc_regs_c = (u32)&cpm2_immr->im_fcc_c[2];
 	}
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
index de8d41a..86a4338 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
@@ -46,4 +46,23 @@ #define MPC85XX_PCI1_MEM_OFFSET	0x000000
 
 #define MPC85XX_PCI1_IO_SIZE	0x01000000
 
+/* FCC1 Clock Source Configuration.  These can be
+ * redefined in the board specific file.
+ *    Can only choose from CLK9-12 */
+#define F1_RXCLK       12
+#define F1_TXCLK       11
+
+/* FCC2 Clock Source Configuration.  These can be
+ * redefined in the board specific file.
+ *    Can only choose from CLK13-16 */
+#define F2_RXCLK       13
+#define F2_TXCLK       14
+
+/* FCC3 Clock Source Configuration.  These can be
+ * redefined in the board specific file.
+ *    Can only choose from CLK13-16 */
+#define F3_RXCLK       15
+#define F3_TXCLK       16
+
+
 #endif				/* __MACH_MPC85XX_ADS_H__ */
diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c
index abb7154..2a35fe2 100644
--- a/arch/ppc/platforms/mpc8272ads_setup.c
+++ b/arch/ppc/platforms/mpc8272ads_setup.c
@@ -56,66 +56,53 @@ static struct fs_uart_platform_info mpc8
 	},
 };
 
-static struct fs_mii_bus_info mii_bus_info = {
-	.method                 = fsmii_bitbang,
-	.id                     = 0,
-	.i.bitbang = {
-		.mdio_port	= fsiop_portc,
-		.mdio_bit	= 18,
-		.mdc_port	= fsiop_portc,
-		.mdc_bit	= 19,
-		.delay		= 1,
-	},
-};
-
-static struct fs_platform_info mpc82xx_fcc1_pdata = {
-	.fs_no		= fsid_fcc1,
-	.cp_page	= CPM_CR_FCC1_PAGE,
-	.cp_block 	= CPM_CR_FCC1_SBLOCK,
-	.clk_trx 	= (PC_F1RXCLK | PC_F1TXCLK),
-	.clk_route	= CMX1_CLK_ROUTE,
-	.clk_mask	= CMX1_CLK_MASK,
-	.init_ioports 	= init_fcc1_ioports,
-
-	.phy_addr	= 0,
-#ifdef PHY_INTERRUPT
-	.phy_irq	= PHY_INTERRUPT,
-#else
-	.phy_irq	= -1;
-#endif
-	.mem_offset	= FCC1_MEM_OFFSET,
-	.bus_info	= &mii_bus_info,
-	.rx_ring	= 32,
-	.tx_ring	= 32,
-	.rx_copybreak	= 240,
-	.use_napi	= 0,
-	.napi_weight	= 17,
-};
-
-static struct fs_platform_info mpc82xx_fcc2_pdata = {
-	.fs_no		= fsid_fcc2,
-	.cp_page	= CPM_CR_FCC2_PAGE,
-	.cp_block 	= CPM_CR_FCC2_SBLOCK,
-	.clk_trx 	= (PC_F2RXCLK | PC_F2TXCLK),
-	.clk_route	= CMX2_CLK_ROUTE,
-	.clk_mask	= CMX2_CLK_MASK,
-	.init_ioports	= init_fcc2_ioports,
-
-	.phy_addr	= 3,
-#ifdef PHY_INTERRUPT
-	.phy_irq	= PHY_INTERRUPT,
-#else
-	.phy_irq	= -1;
-#endif
-	.mem_offset	= FCC2_MEM_OFFSET,
-	.bus_info	= &mii_bus_info,
-	.rx_ring	= 32,
-	.tx_ring	= 32,
-	.rx_copybreak	= 240,
-	.use_napi	= 0,
-	.napi_weight	= 17,
-};
-
+static struct fs_mii_bb_platform_info m82xx_mii_bb_pdata = {
+	.mdio_dat.bit	= 18,
+	.mdio_dir.bit	= 18,
+	.mdc_dat.bit	= 19,
+	.delay		= 1,
+};
+
+static struct fs_platform_info mpc82xx_enet_pdata[] = {
+	[fsid_fcc1] = {
+		.fs_no		= fsid_fcc1,
+		.cp_page	= CPM_CR_FCC1_PAGE,
+		.cp_block 	= CPM_CR_FCC1_SBLOCK,
+
+		.clk_trx 	= (PC_F1RXCLK | PC_F1TXCLK),
+		.clk_route	= CMX1_CLK_ROUTE,
+		.clk_mask	= CMX1_CLK_MASK,
+		.init_ioports 	= init_fcc1_ioports,
+
+		.mem_offset	= FCC1_MEM_OFFSET,
+
+		.rx_ring	= 32,
+		.tx_ring	= 32,
+		.rx_copybreak	= 240,
+		.use_napi	= 0,
+		.napi_weight	= 17,
+		.bus_id		= "0:00",
+	},
+	[fsid_fcc2] = {
+		.fs_no		= fsid_fcc2,
+		.cp_page	= CPM_CR_FCC2_PAGE,
+		.cp_block 	= CPM_CR_FCC2_SBLOCK,
+		.clk_trx 	= (PC_F2RXCLK | PC_F2TXCLK),
+		.clk_route	= CMX2_CLK_ROUTE,
+		.clk_mask	= CMX2_CLK_MASK,
+		.init_ioports	= init_fcc2_ioports,
+
+		.mem_offset	= FCC2_MEM_OFFSET,
+
+		.rx_ring	= 32,
+		.tx_ring	= 32,
+		.rx_copybreak	= 240,
+		.use_napi	= 0,
+		.napi_weight	= 17,
+		.bus_id		= "0:03",
+	},
+};
+
 static void init_fcc1_ioports(void)
 {
 	struct io_port *io;
@@ -209,20 +196,21 @@ static void __init mpc8272ads_fixup_enet
 	bd_t* bi = (void*)__res;
 	int fs_no = fsid_fcc1+pdev->id-1;
 
-	mpc82xx_fcc1_pdata.dpram_offset = mpc82xx_fcc2_pdata.dpram_offset = (u32)cpm2_immr->im_dprambase;
-	mpc82xx_fcc1_pdata.fcc_regs_c = mpc82xx_fcc2_pdata.fcc_regs_c = (u32)cpm2_immr->im_fcc_c;
-
-	switch(fs_no) {
-		case fsid_fcc1:
-			memcpy(&mpc82xx_fcc1_pdata.macaddr,bi->bi_enetaddr,6);
-			pdev->dev.platform_data = &mpc82xx_fcc1_pdata;
-		break;
-		case fsid_fcc2:
-			memcpy(&mpc82xx_fcc2_pdata.macaddr,bi->bi_enetaddr,6);
-			mpc82xx_fcc2_pdata.macaddr[5] ^= 1;
-			pdev->dev.platform_data = &mpc82xx_fcc2_pdata;
-		break;
+	if(fs_no > ARRAY_SIZE(mpc82xx_enet_pdata)) {
+		return;
 	}
+
+	mpc82xx_enet_pdata[fs_no].dpram_offset=
+			(u32)cpm2_immr->im_dprambase;
+	mpc82xx_enet_pdata[fs_no].fcc_regs_c =
+			(u32)cpm2_immr->im_fcc_c;
+	memcpy(&mpc82xx_enet_pdata[fs_no].macaddr,bi->bi_enetaddr,6);
+
+	/* prevent dup mac */
+	if(fs_no == fsid_fcc2)
+		mpc82xx_enet_pdata[fs_no].macaddr[5] ^= 1;
+
+	pdev->dev.platform_data = &mpc82xx_enet_pdata[fs_no];
 }
 
 static void mpc8272ads_fixup_uart_pdata(struct platform_device *pdev,
@@ -272,6 +260,29 @@ static void init_scc4_uart_ioports(void)
 	setbits32(&immap->im_cpmux.cmx_scr,0x0000001b);
 
 	iounmap(immap);
+}
+
+static void __init mpc8272ads_fixup_mdio_pdata(struct platform_device *pdev,
+					      int idx)
+{
+	m82xx_mii_bb_pdata.irq[0] = PHY_INTERRUPT;
+	m82xx_mii_bb_pdata.irq[1] = -1;
+	m82xx_mii_bb_pdata.irq[2] = -1;
+	m82xx_mii_bb_pdata.irq[3] = PHY_INTERRUPT;
+	m82xx_mii_bb_pdata.irq[31] = -1;
+
+
+	m82xx_mii_bb_pdata.mdio_dat.offset =
+				(u32)&cpm2_immr->im_ioport.iop_pdatc;
+
+	m82xx_mii_bb_pdata.mdio_dir.offset =
+				(u32)&cpm2_immr->im_ioport.iop_pdirc;
+
+	m82xx_mii_bb_pdata.mdc_dat.offset =
+				(u32)&cpm2_immr->im_ioport.iop_pdatc;
+
+
+	pdev->dev.platform_data = &m82xx_mii_bb_pdata;
 }
 
 static int mpc8272ads_platform_notify(struct device *dev)
@@ -284,6 +295,10 @@ static int mpc8272ads_platform_notify(st
 		{
 			.bus_id = "fsl-cpm-scc:uart",
 			.rtn = mpc8272ads_fixup_uart_pdata,
+		},
+		{
+			.bus_id = "fsl-bb-mdio",
+			.rtn = mpc8272ads_fixup_mdio_pdata,
 		},
 		{
 			.bus_id = NULL
@@ -319,6 +334,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC4
 	ppc_sys_device_enable(MPC82xx_CPM_SCC4);
 #endif
 
+	ppc_sys_device_enable(MPC82xx_MDIO_BB);
 
 	return 0;
 }
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
index d919dab..ed71dd9 100644
--- a/arch/ppc/platforms/mpc866ads_setup.c
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -1,10 +1,10 @@
-/*arch/ppc/platforms/mpc885ads-setup.c
+/*arch/ppc/platforms/mpc866ads-setup.c
  *
- * Platform setup for the Freescale mpc885ads board
+ * Platform setup for the Freescale mpc866ads board
  *
  * Vitaly Bordug <vbordug@ru.mvista.com>
  *
- * Copyright 2005 MontaVista Software Inc.
+ * Copyright 2005-2006 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
@@ -43,49 +43,36 @@ static void setup_scc1_ioports(void);
 static void setup_smc1_ioports(void);
 static void setup_smc2_ioports(void);
 
-static struct fs_mii_bus_info fec_mii_bus_info = {
-	.method = fsmii_fec,
-	.id = 0,
-};
-
-static struct fs_mii_bus_info scc_mii_bus_info = {
-	.method = fsmii_fixed,
-	.id = 0,
-	.i.fixed.speed = 10,
-	.i.fixed.duplex = 0,
-};
+static struct fs_mii_fec_platform_info	mpc8xx_mdio_fec_pdata;
 
-static struct fs_platform_info mpc8xx_fec_pdata[] = {
-	{
-	 .rx_ring = 128,
-	 .tx_ring = 16,
-	 .rx_copybreak = 240,
+static struct fs_mii_fec_platform_info mpc8xx_mdio_fec_pdata;
 
-	 .use_napi = 1,
-	 .napi_weight = 17,
+static struct fs_platform_info mpc8xx_enet_pdata[] = {
+	[fsid_fec1] = {
+		.rx_ring = 128,
+		.tx_ring = 16,
+		.rx_copybreak = 240,
 
-	 .phy_addr = 15,
-	 .phy_irq = -1,
+		.use_napi = 1,
+		.napi_weight = 17,
 
-	 .use_rmii = 0,
+		.init_ioports = setup_fec1_ioports,
 
-	 .bus_info = &fec_mii_bus_info,
-	 }
-};
+		.bus_id = "0:0f",
+		.has_phy = 1,
+	},
+	[fsid_scc1] = {
+		.rx_ring = 64,
+		.tx_ring = 8,
+		.rx_copybreak = 240,
+		.use_napi = 1,
+		.napi_weight = 17,
 
-static struct fs_platform_info mpc8xx_scc_pdata = {
-	.rx_ring = 64,
-	.tx_ring = 8,
-	.rx_copybreak = 240,
 
-	.use_napi = 1,
-	.napi_weight = 17,
+		.init_ioports = setup_scc1_ioports,
 
-	.phy_addr = -1,
-	.phy_irq = -1,
-
-	.bus_info = &scc_mii_bus_info,
-
+		.bus_id = "fixed@100:1",
+	},
 };
 
 static struct fs_uart_platform_info mpc866_uart_pdata[] = {
@@ -207,64 +194,7 @@ static void setup_scc1_ioports(void)
 	setbits32(&immap->im_cpm.cp_pbdir, PB_ENET_TENA);
 
 }
-
-static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
-{
-	struct fs_platform_info *fpi = pdev->dev.platform_data;
-
-	volatile cpm8xx_t *cp;
-	bd_t *bd = (bd_t *) __res;
-	char *e;
-	int i;
-
-	/* Get pointer to Communication Processor */
-	cp = cpmp;
-	switch (fs_no) {
-	case fsid_fec1:
-		fpi = &mpc8xx_fec_pdata[0];
-		fpi->init_ioports = &setup_fec1_ioports;
 
-		break;
-	case fsid_scc1:
-		fpi = &mpc8xx_scc_pdata;
-		fpi->init_ioports = &setup_scc1_ioports;
-
-		break;
-	default:
-		printk(KERN_WARNING"Device %s is not supported!\n", pdev->name);
-		return;
-	}
-
-	pdev->dev.platform_data = fpi;
-	fpi->fs_no = fs_no;
-
-	e = (unsigned char *)&bd->bi_enetaddr;
-	for (i = 0; i < 6; i++)
-		fpi->macaddr[i] = *e++;
-
-	fpi->macaddr[5 - pdev->id]++;
-
-}
-
-static void mpc866ads_fixup_fec_enet_pdata(struct platform_device *pdev,
-					   int idx)
-{
-	/* This is for FEC devices only */
-	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-fec")))
-		return;
-	mpc866ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
-}
-
-static void mpc866ads_fixup_scc_enet_pdata(struct platform_device *pdev,
-					   int idx)
-{
-	/* This is for SCC devices only */
-	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-scc")))
-		return;
-
-	mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
-}
-
 static void setup_smc1_ioports(void)
 {
 	immap_t *immap = (immap_t *) IMAP_ADDR;
@@ -315,7 +245,57 @@ #else
 #endif
 
 }
+
+static int ma_count = 0;
 
+static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
+{
+	struct fs_platform_info *fpi;
+
+	volatile cpm8xx_t *cp;
+	bd_t *bd = (bd_t *) __res;
+	char *e;
+	int i;
+
+	/* Get pointer to Communication Processor */
+	cp = cpmp;
+
+	if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) {
+		printk(KERN_ERR"No network-suitable #%d device on bus", fs_no);
+		return;
+	}
+
+
+	fpi = &mpc8xx_enet_pdata[fs_no];
+	fpi->fs_no = fs_no;
+	pdev->dev.platform_data = fpi;
+
+	e = (unsigned char *)&bd->bi_enetaddr;
+	for (i = 0; i < 6; i++)
+		fpi->macaddr[i] = *e++;
+
+	fpi->macaddr[5] += ma_count++;
+}
+
+static void mpc866ads_fixup_fec_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for FEC devices only */
+	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-fec")))
+		return;
+	mpc866ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
+}
+
+static void mpc866ads_fixup_scc_enet_pdata(struct platform_device *pdev,
+					   int idx)
+{
+	/* This is for SCC devices only */
+	if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-scc")))
+		return;
+
+	mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
+}
+
 static void __init mpc866ads_fixup_uart_pdata(struct platform_device *pdev,
                                               int idx)
 {
@@ -360,6 +340,9 @@ static int mpc866ads_platform_notify(str
 
 int __init mpc866ads_init(void)
 {
+	bd_t *bd = (bd_t *) __res;
+	struct fs_mii_fec_platform_info* fmpi;
+
 	printk(KERN_NOTICE "mpc866ads: Init\n");
 
 	platform_notify = mpc866ads_platform_notify;
@@ -367,11 +350,20 @@ int __init mpc866ads_init(void)
 	ppc_sys_device_initfunc();
 	ppc_sys_device_disable_all();
 
-#ifdef MPC8xx_SECOND_ETH_SCC1
+#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC1
 	ppc_sys_device_enable(MPC8xx_CPM_SCC1);
 #endif
 	ppc_sys_device_enable(MPC8xx_CPM_FEC1);
+
+	ppc_sys_device_enable(MPC8xx_MDIO_FEC);
+
+	fmpi = ppc_sys_platform_devices[MPC8xx_MDIO_FEC].dev.platform_data =
+		&mpc8xx_mdio_fec_pdata;
 
+	fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1;
+	/* No PHY interrupt line here */
+	fmpi->irq[0xf] = -1;
+
 /* Since either of the uarts could be used as console, they need to ready */
 #ifdef CONFIG_SERIAL_CPM_SMC1
 	ppc_sys_device_enable(MPC8xx_CPM_SMC1);
@@ -382,6 +374,14 @@ #ifdef CONFIG_SERIAL_CPM_SMC
 	ppc_sys_device_enable(MPC8xx_CPM_SMC2);
 	ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART);
 #endif
+	ppc_sys_device_enable(MPC8xx_MDIO_FEC);
+
+	fmpi = ppc_sys_platform_devices[MPC8xx_MDIO_FEC].dev.platform_data =
+		&mpc8xx_mdio_fec_pdata;
+
+	fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1;
+	/* No PHY interrupt line here */
+	fmpi->irq[0xf] = -1;
 
 	return 0;
 }
diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c
index 4b88679..97b3002 100644
--- a/arch/ppc/platforms/mpc885ads_setup.c
+++ b/arch/ppc/platforms/mpc885ads_setup.c
@@ -39,8 +39,11 @@ extern unsigned char __res[];
 static void setup_smc1_ioports(void);
 static void setup_smc2_ioports(void);
 
-static void __init mpc885ads_scc_phy_init(char);
-
+static struct fs_mii_fec_platform_info	mpc8xx_mdio_fec_pdata;
+static void setup_fec1_ioports(void);
+static void setup_fec2_ioports(void);
+static void setup_scc3_ioports(void);
+
 static struct fs_uart_platform_info mpc885_uart_pdata[] = {
 	[fsid_smc1_uart] = {
 		.brg		= 1,
@@ -60,25 +63,10 @@ static struct fs_uart_platform_info mpc8
 		.rx_num_fifo	= 4,
 		.rx_buf_size	= 32,
  	},
-};
-
-static struct fs_mii_bus_info fec_mii_bus_info = {
-	.method = fsmii_fec,
-	.id = 0,
-};
-
-static struct fs_mii_bus_info scc_mii_bus_info = {
-#ifdef CONFIG_SCC_ENET_8xx_FIXED
-	.method = fsmii_fixed,
-#else
-	.method = fsmii_fec,
-#endif
-
-	.id = 0,
 };
 
-static struct fs_platform_info mpc8xx_fec_pdata[] = {
-	{
+static struct fs_platform_info mpc8xx_enet_pdata[] = {
+	[fsid_fec1] = {
 	 .rx_ring = 128,
 	 .tx_ring = 16,
 	 .rx_copybreak = 240,
@@ -86,47 +74,45 @@ static struct fs_platform_info mpc8xx_fe
 	 .use_napi = 1,
 	 .napi_weight = 17,
 
-	 .phy_addr = 0,
-	 .phy_irq = SIU_IRQ7,
+	 .init_ioports = setup_fec1_ioports,
 
-	 .bus_info = &fec_mii_bus_info,
-	 }, {
+          .bus_id = "0:00",
+          .has_phy = 1,
+	 },
+	[fsid_fec2] = {
 	     .rx_ring = 128,
 	     .tx_ring = 16,
 	     .rx_copybreak = 240,
 
 	     .use_napi = 1,
 	     .napi_weight = 17,
-
-	     .phy_addr = 1,
-	     .phy_irq = SIU_IRQ7,
 
-	     .bus_info = &fec_mii_bus_info,
-	     }
-};
+	     .init_ioports = setup_fec2_ioports,
 
-static struct fs_platform_info mpc8xx_scc_pdata = {
-	.rx_ring = 64,
-	.tx_ring = 8,
-	.rx_copybreak = 240,
+ 	     .bus_id = "0:01",
+ 	     .has_phy = 1,
+	     },
+	[fsid_scc3] = {
+		.rx_ring = 64,
+		.tx_ring = 8,
+		.rx_copybreak = 240,
 
-	.use_napi = 1,
-	.napi_weight = 17,
+		.use_napi = 1,
+		.napi_weight = 17,
 
-	.phy_addr = 2,
-#ifdef CONFIG_MPC8xx_SCC_ENET_FIXED
-	.phy_irq = -1,
+		.init_ioports = setup_scc3_ioports,
+#ifdef CONFIG_FIXED_MII_10_FDX
+		.bus_id = "fixed@100:1",
 #else
-	.phy_irq = SIU_IRQ7,
-#endif
-
-	.bus_info = &scc_mii_bus_info,
+		.bus_id = "0:02",
+ #endif
+	},
 };
 
 void __init board_init(void)
 {
-	volatile cpm8xx_t *cp = cpmp;
-	unsigned int *bcsr_io;
+	cpm8xx_t *cp = cpmp;
+ 	unsigned int *bcsr_io;
 
 #ifdef CONFIG_FS_ENET
 	immap_t *immap = (immap_t *) IMAP_ADDR;
@@ -165,6 +151,14 @@ #ifdef CONFIG_FS_ENET
 	/* use MDC for MII (common) */
 	setbits16(&immap->im_ioport.iop_pdpar, 0x0080);
 	clrbits16(&immap->im_ioport.iop_pddir, 0x0080);
+	bcsr_io = ioremap(BCSR5, sizeof(unsigned long));
+	clrbits32(bcsr_io,BCSR5_MII1_EN);
+	clrbits32(bcsr_io,BCSR5_MII1_RST);
+#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
+	clrbits32(bcsr_io,BCSR5_MII2_EN);
+	clrbits32(bcsr_io,BCSR5_MII2_RST);
+#endif
+	iounmap(bcsr_io);
 #endif
 }
 
@@ -195,8 +189,8 @@ static void setup_fec2_ioports(void)
 	/* configure FEC2 pins */
 	setbits32(&immap->im_cpm.cp_pepar, 0x0003fffc);
 	setbits32(&immap->im_cpm.cp_pedir, 0x0003fffc);
-	setbits32(&immap->im_cpm.cp_peso, 0x00037800);
 	clrbits32(&immap->im_cpm.cp_peso, 0x000087fc);
+	setbits32(&immap->im_cpm.cp_peso, 0x00037800);
 	clrbits32(&immap->im_cpm.cp_cptr, 0x00000080);
 }
 
@@ -214,6 +208,8 @@ static void setup_scc3_ioports(void)
 
 	/* Enable the PHY.
 	 */
+	clrbits32(bcsr_io+4, BCSR4_ETH10_RST);
+	udelay(1000);
 	setbits32(bcsr_io+4, BCSR4_ETH10_RST);
 	/* Configure port A pins for Txd and Rxd.
 	 */
@@ -255,37 +251,38 @@ static void setup_scc3_ioports(void)
 	clrbits32(&immap->im_cpm.cp_pedir, PE_ENET_TENA);
 	setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA);
 
-	setbits32(bcsr_io+1, BCSR1_ETHEN);
+	setbits32(bcsr_io+4, BCSR1_ETHEN);
 	iounmap(bcsr_io);
 }
+
+static int mac_count = 0;
 
 static void mpc885ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
 {
-	struct fs_platform_info *fpi = pdev->dev.platform_data;
-
-	volatile cpm8xx_t *cp;
+ 	struct fs_platform_info *fpi;
 	bd_t *bd = (bd_t *) __res;
 	char *e;
 	int i;
+
+	if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) {
+		printk(KERN_ERR"No network-suitable #%d device on bus", fs_no);
+		return;
+	}
+
+	fpi = &mpc8xx_enet_pdata[fs_no];
 
-	/* Get pointer to Communication Processor */
-	cp = cpmp;
 	switch (fs_no) {
 	case fsid_fec1:
-		fpi = &mpc8xx_fec_pdata[0];
 		fpi->init_ioports = &setup_fec1_ioports;
 		break;
 	case fsid_fec2:
-		fpi = &mpc8xx_fec_pdata[1];
 		fpi->init_ioports = &setup_fec2_ioports;
 		break;
 	case fsid_scc3:
-		fpi = &mpc8xx_scc_pdata;
 		fpi->init_ioports = &setup_scc3_ioports;
-		mpc885ads_scc_phy_init(fpi->phy_addr);
 		break;
 	default:
-    	        printk(KERN_WARNING"Device %s is not supported!\n", pdev->name);
+    	        printk(KERN_WARNING "Device %s is not supported!\n", pdev->name);
 	        return;
 	}
 
@@ -296,7 +293,7 @@ static void mpc885ads_fixup_enet_pdata(s
 	for (i = 0; i < 6; i++)
 		fpi->macaddr[i] = *e++;
 
-	fpi->macaddr[5 - pdev->id]++;
+	fpi->macaddr[5] += mac_count++;
 
 }
 
@@ -319,58 +316,6 @@ static void __init mpc885ads_fixup_scc_e
 	mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
 }
 
-/* SCC ethernet controller does not have MII management channel. FEC1 MII
- * channel is used to communicate with the 10Mbit PHY.
- */
-
-#define MII_ECNTRL_PINMUX        0x4
-#define FEC_ECNTRL_PINMUX        0x00000004
-#define FEC_RCNTRL_MII_MODE        0x00000004
-
-/* Make MII read/write commands.
- */
-#define mk_mii_write(REG, VAL, PHY_ADDR)    (0x50020000 | (((REG) & 0x1f) << 18) | \
-                ((VAL) & 0xffff) | ((PHY_ADDR) << 23))
-
-static void mpc885ads_scc_phy_init(char phy_addr)
-{
-	volatile immap_t *immap;
-	volatile fec_t *fecp;
-	bd_t *bd;
-
-	bd = (bd_t *) __res;
-	immap = (immap_t *) IMAP_ADDR;	/* pointer to internal registers */
-	fecp = &(immap->im_cpm.cp_fec);
-
-	/* Enable MII pins of the FEC1
-	 */
-	setbits16(&immap->im_ioport.iop_pdpar, 0x0080);
-	clrbits16(&immap->im_ioport.iop_pddir, 0x0080);
-	/* Set MII speed to 2.5 MHz
-	 */
-	out_be32(&fecp->fec_mii_speed,
-		 ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1);
-
-	/* Enable FEC pin MUX
-	 */
-	setbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX);
-	setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
-
-	out_be32(&fecp->fec_mii_data,
-		 mk_mii_write(MII_BMCR, BMCR_ISOLATE, phy_addr));
-	udelay(100);
-	out_be32(&fecp->fec_mii_data,
-		 mk_mii_write(MII_ADVERTISE,
-			      ADVERTISE_10HALF | ADVERTISE_CSMA, phy_addr));
-	udelay(100);
-
-	/* Disable FEC MII settings
-	 */
-	clrbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX);
-	clrbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
-	out_be32(&fecp->fec_mii_speed, 0);
-}
-
 static void setup_smc1_ioports(void)
 {
         immap_t *immap = (immap_t *) IMAP_ADDR;
@@ -463,6 +408,9 @@ static int mpc885ads_platform_notify(str
 
 int __init mpc885ads_init(void)
 {
+	struct fs_mii_fec_platform_info* fmpi;
+	bd_t *bd = (bd_t *) __res;
+
 	printk(KERN_NOTICE "mpc885ads: Init\n");
 
 	platform_notify = mpc885ads_platform_notify;
@@ -471,9 +419,18 @@ int __init mpc885ads_init(void)
 	ppc_sys_device_disable_all();
 
 	ppc_sys_device_enable(MPC8xx_CPM_FEC1);
+
+	ppc_sys_device_enable(MPC8xx_MDIO_FEC);
+	fmpi = ppc_sys_platform_devices[MPC8xx_MDIO_FEC].dev.platform_data =
+		&mpc8xx_mdio_fec_pdata;
+
+	fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1;
+
+	/* No PHY interrupt line here */
+	fmpi->irq[0xf] = SIU_IRQ7;
 
 #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
-	ppc_sys_device_enable(MPC8xx_CPM_SCC1);
+	ppc_sys_device_enable(MPC8xx_CPM_SCC3);
 
 #endif
 #ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
diff --git a/arch/ppc/platforms/pq2ads_pd.h b/arch/ppc/platforms/pq2ads_pd.h
index 8f14a43..672483d 100644
--- a/arch/ppc/platforms/pq2ads_pd.h
+++ b/arch/ppc/platforms/pq2ads_pd.h
@@ -29,86 +29,4 @@ #define F2_TXCLK	16
 #define F3_RXCLK	13
 #define F3_TXCLK	14
 
-/* Automatically generates register configurations */
-#define PC_CLK(x)	((uint)(1<<(x-1)))	/* FCC CLK I/O ports */
-
-#define CMXFCR_RF1CS(x)	((uint)((x-5)<<27))	/* FCC1 Receive Clock Source */
-#define CMXFCR_TF1CS(x)	((uint)((x-5)<<24))	/* FCC1 Transmit Clock Source */
-#define CMXFCR_RF2CS(x)	((uint)((x-9)<<19))	/* FCC2 Receive Clock Source */
-#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16))	/* FCC2 Transmit Clock Source */
-#define CMXFCR_RF3CS(x)	((uint)((x-9)<<11))	/* FCC3 Receive Clock Source */
-#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8))	/* FCC3 Transmit Clock Source */
-
-#define PC_F1RXCLK	PC_CLK(F1_RXCLK)
-#define PC_F1TXCLK	PC_CLK(F1_TXCLK)
-#define CMX1_CLK_ROUTE	(CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK))
-#define CMX1_CLK_MASK	((uint)0xff000000)
-
-#define PC_F2RXCLK	PC_CLK(F2_RXCLK)
-#define PC_F2TXCLK	PC_CLK(F2_TXCLK)
-#define CMX2_CLK_ROUTE	(CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK))
-#define CMX2_CLK_MASK	((uint)0x00ff0000)
-
-#define PC_F3RXCLK	PC_CLK(F3_RXCLK)
-#define PC_F3TXCLK	PC_CLK(F3_TXCLK)
-#define CMX3_CLK_ROUTE	(CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK))
-#define CMX3_CLK_MASK	((uint)0x0000ff00)
-
-/* I/O Pin assignment for FCC1.  I don't yet know the best way to do this,
- * but there is little variation among the choices.
- */
-#define PA1_COL		0x00000001U
-#define PA1_CRS		0x00000002U
-#define PA1_TXER	0x00000004U
-#define PA1_TXEN	0x00000008U
-#define PA1_RXDV	0x00000010U
-#define PA1_RXER	0x00000020U
-#define PA1_TXDAT	0x00003c00U
-#define PA1_RXDAT	0x0003c000U
-#define PA1_PSORA0	(PA1_RXDAT | PA1_TXDAT)
-#define PA1_PSORA1	(PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \
-		PA1_RXDV | PA1_RXER)
-#define PA1_DIRA0	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
-#define PA1_DIRA1	(PA1_TXDAT | PA1_TXEN | PA1_TXER)
-
-
-/* I/O Pin assignment for FCC2.  I don't yet know the best way to do this,
- * but there is little variation among the choices.
- */
-#define PB2_TXER	0x00000001U
-#define PB2_RXDV	0x00000002U
-#define PB2_TXEN	0x00000004U
-#define PB2_RXER	0x00000008U
-#define PB2_COL		0x00000010U
-#define PB2_CRS		0x00000020U
-#define PB2_TXDAT	0x000003c0U
-#define PB2_RXDAT	0x00003c00U
-#define PB2_PSORB0	(PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \
-		PB2_RXER | PB2_RXDV | PB2_TXER)
-#define PB2_PSORB1	(PB2_TXEN)
-#define PB2_DIRB0	(PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)
-#define PB2_DIRB1	(PB2_TXDAT | PB2_TXEN | PB2_TXER)
-
-
-/* I/O Pin assignment for FCC3.  I don't yet know the best way to do this,
- * but there is little variation among the choices.
- */
-#define PB3_RXDV	0x00004000U
-#define PB3_RXER	0x00008000U
-#define PB3_TXER	0x00010000U
-#define PB3_TXEN	0x00020000U
-#define PB3_COL		0x00040000U
-#define PB3_CRS		0x00080000U
-#define PB3_TXDAT	0x0f000000U
-#define PB3_RXDAT	0x00f00000U
-#define PB3_PSORB0	(PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \
-		PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)
-#define PB3_PSORB1	0
-#define PB3_DIRB0	(PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)
-#define PB3_DIRB1	(PB3_TXDAT | PB3_TXEN | PB3_TXER)
-
-#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
-#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
-#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
-
 #endif
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
index 7735336..325136e 100644
--- a/arch/ppc/syslib/mpc85xx_devices.c
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -16,9 +16,11 @@ #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/serial_8250.h>
 #include <linux/fsl_devices.h>
+#include <linux/fs_enet_pd.h>
 #include <asm/mpc85xx.h>
 #include <asm/irq.h>
 #include <asm/ppc_sys.h>
+#include <asm/cpm2.h>
 
 /* We use offsets for IORESOURCE_MEM since we do not know at compile time
  * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup
@@ -82,6 +84,60 @@ static struct fsl_i2c_platform_data mpc8
 	.device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
 };
 
+static struct fs_platform_info mpc85xx_fcc1_pdata = {
+	.fs_no          = fsid_fcc1,
+	.cp_page        = CPM_CR_FCC1_PAGE,
+	.cp_block       = CPM_CR_FCC1_SBLOCK,
+
+	.rx_ring        = 32,
+	.tx_ring        = 32,
+	.rx_copybreak   = 240,
+	.use_napi       = 0,
+	.napi_weight    = 17,
+
+	.clk_mask	= CMX1_CLK_MASK,
+	.clk_route	= CMX1_CLK_ROUTE,
+	.clk_trx	= (PC_F1RXCLK | PC_F1TXCLK),
+
+	.mem_offset     = FCC1_MEM_OFFSET,
+};
+
+static struct fs_platform_info mpc85xx_fcc2_pdata = {
+	.fs_no          = fsid_fcc2,
+	.cp_page        = CPM_CR_FCC2_PAGE,
+	.cp_block       = CPM_CR_FCC2_SBLOCK,
+
+	.rx_ring        = 32,
+	.tx_ring        = 32,
+	.rx_copybreak   = 240,
+	.use_napi       = 0,
+	.napi_weight    = 17,
+
+	.clk_mask	= CMX2_CLK_MASK,
+	.clk_route	= CMX2_CLK_ROUTE,
+	.clk_trx	= (PC_F2RXCLK | PC_F2TXCLK),
+
+	.mem_offset     = FCC2_MEM_OFFSET,
+};
+
+static struct fs_platform_info mpc85xx_fcc3_pdata = {
+	.fs_no          = fsid_fcc3,
+	.cp_page        = CPM_CR_FCC3_PAGE,
+	.cp_block       = CPM_CR_FCC3_SBLOCK,
+
+	.rx_ring        = 32,
+	.tx_ring        = 32,
+	.rx_copybreak   = 240,
+	.use_napi       = 0,
+	.napi_weight    = 17,
+
+	.clk_mask	= CMX3_CLK_MASK,
+	.clk_route	= CMX3_CLK_ROUTE,
+	.clk_trx	= (PC_F3RXCLK | PC_F3TXCLK),
+
+	.mem_offset     = FCC3_MEM_OFFSET,
+};
+
 static struct plat_serial8250_port serial_platform_data[] = {
 	[0] = {
 		.mapbase	= 0x4500,
@@ -318,19 +374,28 @@ struct platform_device ppc_sys_platform_
 	[MPC85xx_CPM_FCC1] = {
 		.name = "fsl-cpm-fcc",
 		.id	= 1,
-		.num_resources	 = 3,
+		.num_resources	 = 4,
+		.dev.platform_data = &mpc85xx_fcc1_pdata,
 		.resource = (struct resource[]) {
 			{
+				.name	= "fcc_regs",
 				.start	= 0x91300,
 				.end	= 0x9131F,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
+				.name   = "fcc_regs_c",
 				.start	= 0x91380,
 				.end	= 0x9139F,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
+				.name	= "fcc_pram",
+				.start	= 0x88400,
+				.end	= 0x884ff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
 				.start	= SIU_INT_FCC1,
 				.end	= SIU_INT_FCC1,
 				.flags	= IORESOURCE_IRQ,
@@ -340,19 +405,28 @@ struct platform_device ppc_sys_platform_
 	[MPC85xx_CPM_FCC2] = {
 		.name = "fsl-cpm-fcc",
 		.id	= 2,
-		.num_resources	 = 3,
+		.num_resources	 = 4,
+		.dev.platform_data = &mpc85xx_fcc2_pdata,
 		.resource = (struct resource[]) {
 			{
+				.name	= "fcc_regs",
 				.start	= 0x91320,
 				.end	= 0x9133F,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
+				.name   = "fcc_regs_c",
 				.start	= 0x913A0,
 				.end	= 0x913CF,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
+				.name	= "fcc_pram",
+				.start	= 0x88500,
+				.end	= 0x885ff,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
 				.start	= SIU_INT_FCC2,
 				.end	= SIU_INT_FCC2,
 				.flags	= IORESOURCE_IRQ,
@@ -362,16 +436,25 @@ struct platform_device ppc_sys_platform_
 	[MPC85xx_CPM_FCC3] = {
 		.name = "fsl-cpm-fcc",
 		.id	= 3,
-		.num_resources	 = 3,
+		.num_resources	 = 4,
+		.dev.platform_data = &mpc85xx_fcc3_pdata,
 		.resource = (struct resource[]) {
 			{
+				.name	= "fcc_regs",
 				.start	= 0x91340,
 				.end	= 0x9135F,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
+				.name   = "fcc_regs_c",
 				.start	= 0x913D0,
 				.end	= 0x913FF,
+				.flags	= IORESOURCE_MEM,
+			},
+			{
+				.name	= "fcc_pram",
+				.start	= 0x88600,
+				.end	= 0x886ff,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
diff --git a/arch/ppc/syslib/mpc8xx_devices.c b/arch/ppc/syslib/mpc8xx_devices.c
index 6f53638..cf5ab47 100644
--- a/arch/ppc/syslib/mpc8xx_devices.c
+++ b/arch/ppc/syslib/mpc8xx_devices.c
@@ -218,6 +218,14 @@ struct platform_device ppc_sys_platform_
 			},
 		},
 	},
+
+        [MPC8xx_MDIO_FEC] = {
+                .name = "fsl-cpm-fec-mdio",
+                .id = 0,
+                .num_resources = 0,
+
+        },
+
 };
 
 static int __init mach_mpc8xx_fixup(struct platform_device *pdev)
diff --git a/arch/ppc/syslib/mpc8xx_sys.c b/arch/ppc/syslib/mpc8xx_sys.c
index eee2132..18ba1d7 100644
--- a/arch/ppc/syslib/mpc8xx_sys.c
+++ b/arch/ppc/syslib/mpc8xx_sys.c
@@ -22,7 +22,7 @@ struct ppc_sys_spec ppc_sys_specs[] = {
 		.ppc_sys_name	= "MPC86X",
 		.mask 		= 0xFFFFFFFF,
 		.value 		= 0x00000000,
-		.num_devices	= 7,
+		.num_devices	= 8,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC8xx_CPM_FEC1,
@@ -32,13 +32,14 @@ struct ppc_sys_spec ppc_sys_specs[] = {
 			MPC8xx_CPM_SCC4,
 			MPC8xx_CPM_SMC1,
 			MPC8xx_CPM_SMC2,
+			MPC8xx_MDIO_FEC,
 		},
 	},
 	{
 		.ppc_sys_name	= "MPC885",
 		.mask 		= 0xFFFFFFFF,
 		.value 		= 0x00000000,
-		.num_devices	= 8,
+		.num_devices	= 9,
 		.device_list	= (enum ppc_sys_devices[])
 		{
 			MPC8xx_CPM_FEC1,
@@ -49,6 +50,7 @@ struct ppc_sys_spec ppc_sys_specs[] = {
 			MPC8xx_CPM_SCC4,
 			MPC8xx_CPM_SMC1,
 			MPC8xx_CPM_SMC2,
+			MPC8xx_MDIO_FEC,
 		},
 	},
 	{	/* default match */
diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c
index 8692d00..fefbc21 100644
--- a/arch/ppc/syslib/pq2_devices.c
+++ b/arch/ppc/syslib/pq2_devices.c
@@ -369,6 +369,11 @@ struct platform_device ppc_sys_platform_
 			},
 		},
 	},
+	[MPC82xx_MDIO_BB] = {
+		.name = "fsl-bb-mdio",
+		.id = 0,
+		.num_resources = 0,
+	},
 };
 
 static int __init mach_mpc82xx_fixup(struct platform_device *pdev)
diff --git a/arch/ppc/syslib/pq2_sys.c b/arch/ppc/syslib/pq2_sys.c
index fee8948..f52600c 100644
--- a/arch/ppc/syslib/pq2_sys.c
+++ b/arch/ppc/syslib/pq2_sys.c
@@ -139,13 +139,14 @@ struct ppc_sys_spec ppc_sys_specs[] = {
 		.ppc_sys_name	= "8272",
 		.mask		= 0x0000ff00,
 		.value		= 0x00000c00,
-		.num_devices	= 12,
+		.num_devices	= 13,
 		.device_list = (enum ppc_sys_devices[])
 		{
 			MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1,
 			MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SCC4,
 			MPC82xx_CPM_SMC1, MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI,
 			MPC82xx_CPM_I2C, MPC82xx_CPM_USB, MPC82xx_SEC1,
+			MPC82xx_MDIO_BB,
 		},
 	},
 	/* below is a list of the 8280 family of processors */
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
index c70344b..f6a7ff0 100644
--- a/include/asm-ppc/cpm2.h
+++ b/include/asm-ppc/cpm2.h
@@ -1093,5 +1093,100 @@ #endif
 
 #define FCC_PSMR_RMII	((uint)0x00020000)	/* Use RMII interface */
 
+/* FCC iop & clock configuration. BSP code is responsible to define Fx_RXCLK & Fx_TXCLK
+ * in order to use clock-computing stuff below for the FCC x
+ */
+
+/* Automatically generates register configurations */
+#define PC_CLK(x)	((uint)(1<<(x-1)))	/* FCC CLK I/O ports */
+
+#define CMXFCR_RF1CS(x)	((uint)((x-5)<<27))	/* FCC1 Receive Clock Source */
+#define CMXFCR_TF1CS(x)	((uint)((x-5)<<24))	/* FCC1 Transmit Clock Source */
+#define CMXFCR_RF2CS(x)	((uint)((x-9)<<19))	/* FCC2 Receive Clock Source */
+#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16))	/* FCC2 Transmit Clock Source */
+#define CMXFCR_RF3CS(x)	((uint)((x-9)<<11))	/* FCC3 Receive Clock Source */
+#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8))	/* FCC3 Transmit Clock Source */
+
+#define PC_F1RXCLK	PC_CLK(F1_RXCLK)
+#define PC_F1TXCLK	PC_CLK(F1_TXCLK)
+#define CMX1_CLK_ROUTE	(CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK))
+#define CMX1_CLK_MASK	((uint)0xff000000)
+
+#define PC_F2RXCLK	PC_CLK(F2_RXCLK)
+#define PC_F2TXCLK	PC_CLK(F2_TXCLK)
+#define CMX2_CLK_ROUTE	(CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK))
+#define CMX2_CLK_MASK	((uint)0x00ff0000)
+
+#define PC_F3RXCLK	PC_CLK(F3_RXCLK)
+#define PC_F3TXCLK	PC_CLK(F3_TXCLK)
+#define CMX3_CLK_ROUTE	(CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK))
+#define CMX3_CLK_MASK	((uint)0x0000ff00)
+
+#define CPMUX_CLK_MASK (CMX3_CLK_MASK | CMX2_CLK_MASK)
+#define CPMUX_CLK_ROUTE (CMX3_CLK_ROUTE | CMX2_CLK_ROUTE)
+
+#define CLK_TRX (PC_F3TXCLK | PC_F3RXCLK | PC_F2TXCLK | PC_F2RXCLK)
+
+/* I/O Pin assignment for FCC1.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PA1_COL		0x00000001U
+#define PA1_CRS		0x00000002U
+#define PA1_TXER	0x00000004U
+#define PA1_TXEN	0x00000008U
+#define PA1_RXDV	0x00000010U
+#define PA1_RXER	0x00000020U
+#define PA1_TXDAT	0x00003c00U
+#define PA1_RXDAT	0x0003c000U
+#define PA1_PSORA0	(PA1_RXDAT | PA1_TXDAT)
+#define PA1_PSORA1	(PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \
+		PA1_RXDV | PA1_RXER)
+#define PA1_DIRA0	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
+#define PA1_DIRA1	(PA1_TXDAT | PA1_TXEN | PA1_TXER)
+
+
+/* I/O Pin assignment for FCC2.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB2_TXER	0x00000001U
+#define PB2_RXDV	0x00000002U
+#define PB2_TXEN	0x00000004U
+#define PB2_RXER	0x00000008U
+#define PB2_COL		0x00000010U
+#define PB2_CRS		0x00000020U
+#define PB2_TXDAT	0x000003c0U
+#define PB2_RXDAT	0x00003c00U
+#define PB2_PSORB0	(PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \
+		PB2_RXER | PB2_RXDV | PB2_TXER)
+#define PB2_PSORB1	(PB2_TXEN)
+#define PB2_DIRB0	(PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)
+#define PB2_DIRB1	(PB2_TXDAT | PB2_TXEN | PB2_TXER)
+
+
+/* I/O Pin assignment for FCC3.  I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB3_RXDV	0x00004000U
+#define PB3_RXER	0x00008000U
+#define PB3_TXER	0x00010000U
+#define PB3_TXEN	0x00020000U
+#define PB3_COL		0x00040000U
+#define PB3_CRS		0x00080000U
+#define PB3_TXDAT	0x0f000000U
+#define PC3_TXDAT	0x00000010U
+#define PB3_RXDAT	0x00f00000U
+#define PB3_PSORB0	(PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \
+		PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)
+#define PB3_PSORB1	0
+#define PB3_DIRB0	(PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)
+#define PB3_DIRB1	(PB3_TXDAT | PB3_TXEN | PB3_TXER)
+#define PC3_DIRC1	(PC3_TXDAT)
+
+/* Handy macro to specify mem for FCCs*/
+#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
+#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
+#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
+#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
+
 #endif /* __CPM2__ */
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h
index 6ba69a8..e4a897e 100644
--- a/include/asm-ppc/mpc8260.h
+++ b/include/asm-ppc/mpc8260.h
@@ -83,6 +83,7 @@ enum ppc_sys_devices {
 	MPC82xx_CPM_SMC2,
 	MPC82xx_CPM_USB,
 	MPC82xx_SEC1,
+	MPC82xx_MDIO_BB,
 	NUM_PPC_SYS_DEVS,
 };
 
diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h
index 3515a7f..8830dfe 100644
--- a/include/asm-ppc/mpc8xx.h
+++ b/include/asm-ppc/mpc8xx.h
@@ -111,6 +111,7 @@ enum ppc_sys_devices {
 	MPC8xx_CPM_SMC1,
 	MPC8xx_CPM_SMC2,
 	MPC8xx_CPM_USB,
+	MPC8xx_MDIO_FEC,
 	NUM_PPC_SYS_DEVS,
 };
 
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index 783c476..74ed35a 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -69,36 +69,23 @@ enum fs_ioport {
 	fsiop_porte,
 };
 
-struct fs_mii_bus_info {
-	int method;		/* mii method                  */
-	int id;			/* the id of the mii_bus       */
-	int disable_aneg;	/* if the controller needs to negothiate speed & duplex */
-	int lpa; 		/* the default board-specific vallues will be applied otherwise */
-
-	union {
-		struct {
-			int duplex;
-			int speed;
-		} fixed;
-
-		struct {
-			/* nothing */
-		} fec;
-		
-		struct {
-			/* nothing */
-		} scc;
-
-		struct {
-			int mdio_port;	/* port & bit for MDIO */
-			int mdio_bit;
-			int mdc_port;	/* port & bit for MDC  */
-			int mdc_bit;
-			int delay;	/* delay in us         */
-		} bitbang;
-	} i;
-};
-
+struct fs_mii_bit {
+	u32 offset;
+	u8 bit;
+	u8 polarity;
+};
+struct fs_mii_bb_platform_info {
+	struct fs_mii_bit 	mdio_dir;
+	struct fs_mii_bit 	mdio_dat;
+	struct fs_mii_bit	mdc_dat;
+	int mdio_port;	/* port & bit for MDIO */
+	int mdio_bit;
+	int mdc_port;	/* port & bit for MDC  */
+	int mdc_bit;
+	int delay;	/* delay in us         */
+	int irq[32]; 	/* irqs per phy's */
+};
+
 struct fs_platform_info {
 	
 	void(*init_ioports)(void);
@@ -119,6 +106,7 @@ struct fs_platform_info {
 	u32 device_flags;
 
 	int phy_addr;		/* the phy address (-1 no phy) */
+	const char*	bus_id;
 	int phy_irq;		/* the phy irq (if it exists)  */
 
 	const struct fs_mii_bus_info *bus_info;
@@ -130,6 +118,10 @@ struct fs_platform_info {
 	int napi_weight;	/* NAPI weight                 */
 
 	int use_rmii;		/* use RMII mode 	       */
+	int has_phy;            /* if the network is phy container as well...*/
 };
-
+struct fs_mii_fec_platform_info {
+	u32 irq[32];
+	u32 mii_speed;
+};
 #endif

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/6] FS_ENET: phydev pointer may be dereferenced without NULL check
       [not found] <20060623231648.6721.3495.stgit@localhost.localdomain>
                   ` (2 preceding siblings ...)
  2006-06-23 23:17 ` [PATCH 3/6] FS_ENET: use PAL for mii management (BSP part) Vitaly Bordug
@ 2006-06-23 23:17 ` Vitaly Bordug
  2006-06-23 23:17 ` [PATCH 5/6] CPM_UART: unify clock sources Vitaly Bordug
  2006-06-23 23:17 ` [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support Vitaly Bordug
  5 siblings, 0 replies; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-23 23:17 UTC (permalink / raw)
  To: linuxppc-dev


When interface is down, phy is "disconnected" from the bus and phydev is NULL.
But ethtool may try to get/set phy regs even at that time, which results in
NULL pointer dereference and OOPS hereby.

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
---

 drivers/net/fs_enet/fs_enet-main.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 302ecaa..e475e22 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -882,12 +882,16 @@ static void fs_get_regs(struct net_devic
 static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
+	if (!fep->phydev)
+		return -EINVAL;
 	return phy_ethtool_gset(fep->phydev, cmd);
 }
 
 static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
+	if (!fep->phydev)
+		return -EINVAL;
 	phy_ethtool_sset(fep->phydev, cmd);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/6] CPM_UART: unify clock sources
       [not found] <20060623231648.6721.3495.stgit@localhost.localdomain>
                   ` (3 preceding siblings ...)
  2006-06-23 23:17 ` [PATCH 4/6] FS_ENET: phydev pointer may be dereferenced without NULL check Vitaly Bordug
@ 2006-06-23 23:17 ` Vitaly Bordug
  2006-06-24 13:46   ` Kumar Gala
  2006-06-23 23:17 ` [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support Vitaly Bordug
  5 siblings, 1 reply; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-23 23:17 UTC (permalink / raw)
  To: linuxppc-dev


In order to make it possible to utilize the driver from arch/powerpc yet not
breaking existing ppc users, clock sources are unfied via macro, and
resources ioremapped.

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
---

 drivers/serial/cpm_uart/cpm_uart_core.c |   11 ++++-------
 drivers/serial/cpm_uart/cpm_uart_cpm2.c |   13 +++++++------
 include/asm-powerpc/fs_pd.h             |   17 +++++++++++++++++
 include/asm-ppc/fs_pd.h                 |   17 +++++++++++++++++
 4 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 5cba59a..0507f74 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -47,6 +47,7 @@ #include <linux/fs_uart_pd.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
+#include <asm/fs_pd.h>
 
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -1045,11 +1046,11 @@ int cpm_uart_drv_get_platform_data(struc
 
 	if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs")))
 		return -EINVAL;
-	mem = r->start;
+	mem = ioremap(r->start, r->end - r->start + 1);
 
 	if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram")))
 		return -EINVAL;
-	pram = r->start;
+	pram = ioremap(r->start, r->end - r->start + 1);
 
 	if(idx > fsid_smc2_uart) {
 		pinfo->sccp = (scc_t *)mem;
@@ -1190,11 +1191,7 @@ static int __init cpm_uart_console_setup
 	if (options) {
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	} else {
-		bd_t *bd = (bd_t *) __res;
-
-		if (bd->bi_baudrate)
-			baud = bd->bi_baudrate;
-		else
+		if ((baud = GET_BAUDRATE()) == -1)
 			baud = 9600;
 	}
 
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index cdba128..29b89f0 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -41,6 +41,7 @@ #include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/fs_pd.h>
 
 #include <linux/serial_core.h>
 #include <linux/kernel.h>
@@ -267,7 +268,7 @@ #ifdef CONFIG_SERIAL_CPM_SMC1
 	    (unsigned long)&cpm2_immr->im_smc[0];
 	cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
 	cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-	cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SMC1].port.uartclk = FS_UART_CLK();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
 #endif
 
@@ -280,7 +281,7 @@ #ifdef CONFIG_SERIAL_CPM_SMC2
 	    (unsigned long)&cpm2_immr->im_smc[1];
 	cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
 	cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-	cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SMC2].port.uartclk = FS_UART_CLK();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
 #endif
 
@@ -294,7 +295,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC1
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC1].port.uartclk = FS_UART_CLK();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
 #endif
 
@@ -308,7 +309,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC2
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC2].port.uartclk = FS_UART_CLK();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
 #endif
 
@@ -322,7 +323,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC3
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC3].port.uartclk = FS_UART_CLK();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
 #endif
 
@@ -336,7 +337,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC4
 	    ~(UART_SCCM_TX | UART_SCCM_RX);
 	cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
 	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-	cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+	cpm_uart_ports[UART_SCC4].port.uartclk = FS_UART_CLK();
 	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
 #endif
 
diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h
new file mode 100644
index 0000000..b20d8da
--- /dev/null
+++ b/include/asm-powerpc/fs_pd.h
@@ -0,0 +1,17 @@
+/*
+ * Platform information definitions.
+ *
+ * 2006 (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 FS_PD_H
+#define FS_PD_H
+
+#define GET_BAUDRATE()	get_baudrate()
+#define FS_UART_CLK()	get_intfreq()
+
+#endif
diff --git a/include/asm-ppc/fs_pd.h b/include/asm-ppc/fs_pd.h
new file mode 100644
index 0000000..b1d550b
--- /dev/null
+++ b/include/asm-ppc/fs_pd.h
@@ -0,0 +1,17 @@
+/*
+ * Platform information definitions.
+ *
+ * 2006 (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 FS_PD_H
+#define FS_PD_H
+
+#define GET_BAUDRATE()	(((bd_t *) __res)->bi_baudrate ? ((bd_t *) __res)->bi_baudrate : -1)
+#define FS_UART_CLK()	(((bd_t *) __res)->bi_intfreq)
+
+#endif

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support
       [not found] <20060623231648.6721.3495.stgit@localhost.localdomain>
                   ` (4 preceding siblings ...)
  2006-06-23 23:17 ` [PATCH 5/6] CPM_UART: unify clock sources Vitaly Bordug
@ 2006-06-23 23:17 ` Vitaly Bordug
  2006-06-24 16:26   ` Kumar Gala
  5 siblings, 1 reply; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-23 23:17 UTC (permalink / raw)
  To: linuxppc-dev


This enables the mpc8560-specific bits in powerpc. The relevant cpm2 PIC
and common utility were moved without or with minor changes, hereby not all
the stuff have OF power utilized. Current functionality depends on the very
latest fs_enet update, that will go through netdev (cc'd here as
reference). Assuming all the preceeding stuff applied (PAL+fs_enet related
+ CPM_UART update), the both TSEC eth ,FCC Eths, and both SCC UARTs are
working. The relevant drivers are still capable to drive users in ppc,
which was verified with 8272ADS (SCC uart+FCC eth).

Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
---

 arch/powerpc/lib/Makefile                 |    5 +
 arch/powerpc/platforms/85xx/Kconfig       |   11 +
 arch/powerpc/platforms/85xx/Makefile      |    1 
 arch/powerpc/platforms/85xx/mpc8560_ads.h |   54 +++++
 arch/powerpc/platforms/85xx/mpc85xx_ads.c |  107 +++++++++++
 arch/powerpc/sysdev/Makefile              |    7 +
 arch/powerpc/sysdev/cpm2_common.c         |  197 ++++++++++++++++++++
 arch/powerpc/sysdev/cpm2_pic.c            |  181 ++++++++++++++++++
 arch/powerpc/sysdev/cpm2_pic.h            |    8 +
 arch/powerpc/sysdev/fsl_soc.c             |  290 +++++++++++++++++++++++++++++
 include/asm-ppc/cpm2.h                    |    2 
 11 files changed, 860 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index ff70964..0993b3b 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -21,3 +21,8 @@ ifeq ($(CONFIG_PPC64),y)
 obj-$(CONFIG_SMP)	+= locks.o
 obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
 endif
+
+# Temporary hack until we have migrated to asm-powerpc
+ifeq ($(ARCH),powerpc)
+obj-$(CONFIG_CPM2)	+= rheap.o
+endif
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 454fc53..3d440de 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -11,6 +11,12 @@ config MPC8540_ADS
 	help
 	  This option enables support for the MPC 8540 ADS board
 
+config MPC8560_ADS
+	bool "Freescale MPC8560 ADS"
+	select DEFAULT_UIMAGE
+	help
+	  This option enables support for the MPC 8560 ADS board
+
 config MPC85xx_CDS
 	bool "Freescale MPC85xx CDS"
 	select DEFAULT_UIMAGE
@@ -25,6 +31,11 @@ config MPC8540
 	select PPC_UDBG_16550
 	select PPC_INDIRECT_PCI
 	default y if MPC8540_ADS || MPC85xx_CDS
+
+config MPC8560
+	bool
+	select PPC_INDIRECT_PCI
+	default y if MPC8560_ADS
 
 config PPC_INDIRECT_PCI_BE
 	bool
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 7615aa5..282f5d0 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,4 +3,5 @@ # Makefile for the PowerPC 85xx linux ke
 #
 obj-$(CONFIG_PPC_85xx)	+= misc.o pci.o
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
+obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
diff --git a/arch/powerpc/platforms/85xx/mpc8560_ads.h b/arch/powerpc/platforms/85xx/mpc8560_ads.h
new file mode 100644
index 0000000..4ebe710
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc8560_ads.h
@@ -0,0 +1,54 @@
+/*
+ * MPC8560ADS board definitions
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_MPC8560ADS_H
+#define __MACH_MPC8560ADS_H
+
+#include <linux/config.h>
+#include <linux/initrd.h>
+
+#define BOARD_CCSRBAR		((uint)0xe0000000)
+#define BCSR_ADDR		((uint)0xf8000000)
+#define BCSR_SIZE		((uint)(32 * 1024))
+
+#define MPC85xx_CPM_OFFSET	(0x80000)
+
+/*XXX TODO: pull from OF*/
+#define CPM_MAP_ADDR		(BOARD_CCSRBAR + MPC85xx_CPM_OFFSET)
+
+/* PCI interrupt controller */
+#define PIRQA		MPC85xx_IRQ_EXT1
+#define PIRQB		MPC85xx_IRQ_EXT2
+#define PIRQC		MPC85xx_IRQ_EXT3
+#define PIRQD		MPC85xx_IRQ_EXT4
+
+/* FCC1 Clock Source Configuration.  These can be
+ * redefined in the board specific file.
+ *    Can only choose from CLK9-12 */
+#define F1_RXCLK       12
+#define F1_TXCLK       11
+
+/* FCC2 Clock Source Configuration.  These can be
+ * redefined in the board specific file.
+ *    Can only choose from CLK13-16 */
+#define F2_RXCLK       13
+#define F2_TXCLK       14
+
+/* FCC3 Clock Source Configuration.  These can be
+ * redefined in the board specific file.
+ *    Can only choose from CLK13-16 */
+#define F3_RXCLK       15
+#define F3_TXCLK       16
+
+#endif				/* __MACH_MPC8560ADS_H */
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 5eeff37..352d0ae 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -15,6 +15,7 @@ #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
 #include <linux/kdev_t.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
@@ -30,6 +31,10 @@ #include <asm/mpic.h>
 #include <mm/mmu_decl.h>
 #include <asm/udbg.h>
 
+#ifdef CONFIG_CPM2
+#include <asm/cpm2.h>
+#endif
+
 #include <sysdev/fsl_soc.h>
 #include "mpc85xx.h"
 
@@ -121,8 +126,25 @@ mpc85xx_exclude_device(u_char bus, u_cha
 }
 
 #endif /* CONFIG_PCI */
+
+#ifdef CONFIG_CPM2
 
+static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+{
+	while ((irq = cpm2_get_irq(regs)) >= 0)
+		__do_IRQ(irq, regs);
+	return IRQ_HANDLED;
+}
 
+static struct irqaction cpm2_irqaction = {
+	.handler = cpm2_cascade,
+	.flags = SA_INTERRUPT,
+	.mask = CPU_MASK_NONE,
+	.name = "cpm2_cascade",
+};
+
+#endif /* CONFIG_CPM2 */
+
 void __init mpc85xx_ads_pic_init(void)
 {
 	struct mpic *mpic1;
@@ -158,15 +180,91 @@ void __init mpc85xx_ads_pic_init(void)
 	mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
 	mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
 	mpic_init(mpic1);
+
+#ifdef CONFIG_CPM2
+	/* Setup CPM2 PIC */
+
+        cpm2_init_IRQ();
+
+	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
+#endif
 }
 
 /*
  * Setup the architecture
- */
+ */
+static void init_fcc_ioports(void)
+{
+	struct immap *immap;
+	struct io_port *io;
+	u32 tempval;
+
+	immap = cpm2_immr;
+
+	io = &immap->im_ioport;
+	/* FCC2/3 are on the ports B/C. */
+	tempval = in_be32(&io->iop_pdirb);
+	tempval &= ~PB2_DIRB0;
+	tempval |= PB2_DIRB1;
+	out_be32(&io->iop_pdirb, tempval);
+
+	tempval = in_be32(&io->iop_psorb);
+	tempval &= ~PB2_PSORB0;
+	tempval |= PB2_PSORB1;
+	out_be32(&io->iop_psorb, tempval);
+
+	tempval = in_be32(&io->iop_pparb);
+	tempval |= (PB2_DIRB0 | PB2_DIRB1);
+	out_be32(&io->iop_pparb, tempval);
+
+	tempval = in_be32(&io->iop_pdirb);
+	tempval &= ~PB3_DIRB0;
+	tempval |= PB3_DIRB1;
+	out_be32(&io->iop_pdirb, tempval);
+
+	tempval = in_be32(&io->iop_psorb);
+	tempval &= ~PB3_PSORB0;
+	tempval |= PB3_PSORB1;
+	out_be32(&io->iop_psorb, tempval);
+
+	tempval = in_be32(&io->iop_pparb);
+	tempval |= (PB3_DIRB0 | PB3_DIRB1);
+	out_be32(&io->iop_pparb, tempval);
+
+	tempval = in_be32(&io->iop_pdirc);
+	tempval |= PC3_DIRC1;
+	out_be32(&io->iop_pdirc, tempval);
+
+	tempval = in_be32(&io->iop_pparc);
+	tempval |= PC3_DIRC1;
+	out_be32(&io->iop_pparc, tempval);
+
+	/* Port C has clocks......  */
+	tempval = in_be32(&io->iop_psorc);
+	tempval &= ~(CLK_TRX);
+	out_be32(&io->iop_psorc, tempval);
+
+	tempval = in_be32(&io->iop_pdirc);
+	tempval &= ~(CLK_TRX);
+	out_be32(&io->iop_pdirc, tempval);
+	tempval = in_be32(&io->iop_pparc);
+	tempval |= (CLK_TRX);
+	out_be32(&io->iop_pparc, tempval);
+
+	/* Configure Serial Interface clock routing.
+	 * First,  clear all FCC bits to zero,
+	 * then set the ones we want.
+	 */
+	immap->im_cpmux.cmx_fcr &= ~(CPMUX_CLK_MASK);
+	immap->im_cpmux.cmx_fcr |= CPMUX_CLK_ROUTE;
+}
+
 static void __init mpc85xx_ads_setup_arch(void)
 {
 	struct device_node *cpu;
 	struct device_node *np;
+
+	cpm2_reset();
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc85xx_ads_setup_arch()", 0);
@@ -184,8 +282,13 @@ static void __init mpc85xx_ads_setup_arc
 	}
 
 #ifdef CONFIG_PCI
+
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		add_bridge(np);
+
+#ifdef CONFIG_CPM2
+	init_fcc_ioports();
+#endif
 
 	ppc_md.pci_swizzle = common_swizzle;
 	ppc_md.pci_map_irq = mpc85xx_map_irq;
@@ -240,5 +343,7 @@ define_machine(mpc85xx_ads) {
 	.get_irq		= mpic_get_irq,
 	.restart		= mpc85xx_restart,
 	.calibrate_decr		= generic_calibrate_decr,
+#ifndef CONFIG_CPM2
 	.progress		= udbg_progress,
+#endif
 };
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index cef95b0..75dfe12 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,3 +12,10 @@ obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_PPC_83xx)		+= ipic.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
+
+# Temporary hack until we have migrated to asm-powerpc
+ifeq ($(ARCH),powerpc)
+obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
+endif
+
+#obj-$(CONFIG_CPM2)		+= cpm2/			Yuri
diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c
new file mode 100644
index 0000000..c755f65
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_common.c
@@ -0,0 +1,197 @@
+/*
+ * General Purpose functions for the global management of the
+ * 8260 Communication Processor Module.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ *	2.3.99 Updates
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mpc8260.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/cpm2.h>
+#include <asm/rheap.h>
+
+static void cpm2_dpinit(void);
+cpm_cpm2_t	*cpmp;		/* Pointer to comm processor space */
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+cpm2_map_t *cpm2_immr;
+
+#define CPM_MAP_SIZE	(0x40000)	/* 256k - the PQ3 reserve this amount
+					   of space for CPM as it is larger
+					   than on PQ2 */
+
+void
+cpm2_reset(void)
+{
+	cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
+
+	/* Reclaim the DP memory for our use.
+	 */
+	cpm2_dpinit();
+
+	/* Tell everyone where the comm processor resides.
+	 */
+	cpmp = &cpm2_immr->im_cpm;
+}
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks.  The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers).  Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK	(get_brgfreq())
+#define BRG_UART_CLK	(BRG_INT_CLK/16)
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+cpm_setbrg(uint brg, uint rate)
+{
+	volatile uint	*bp;
+
+	/* This is good enough to get SMCs running.....
+	*/
+	if (brg < 4) {
+		bp = (uint *)&cpm2_immr->im_brgc1;
+	}
+	else {
+		bp = (uint *)&cpm2_immr->im_brgc5;
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+cpm2_fastbrg(uint brg, uint rate, int div16)
+{
+	volatile uint	*bp;
+
+	if (brg < 4) {
+		bp = (uint *)&cpm2_immr->im_brgc1;
+	}
+	else {
+		bp = (uint *)&cpm2_immr->im_brgc5;
+		brg -= 4;
+	}
+	bp += brg;
+	*bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
+	if (div16)
+		*bp |= CPM_BRG_DIV16;
+}
+
+/*
+ * dpalloc / dpfree bits.
+ */
+static spinlock_t cpm_dpmem_lock;
+/* 16 blocks should be enough to satisfy all requests
+ * until the memory subsystem goes up... */
+static rh_block_t cpm_boot_dpmem_rh_block[16];
+static rh_info_t cpm_dpmem_info;
+
+static void cpm2_dpinit(void)
+{
+	spin_lock_init(&cpm_dpmem_lock);
+
+	/* initialize the info header */
+	rh_init(&cpm_dpmem_info, 1,
+			sizeof(cpm_boot_dpmem_rh_block) /
+			sizeof(cpm_boot_dpmem_rh_block[0]),
+			cpm_boot_dpmem_rh_block);
+
+	/* Attach the usable dpmem area */
+	/* XXX: This is actually crap. CPM_DATAONLY_BASE and
+	 * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
+	 * varies with the processor and the microcode patches activated.
+	 * But the following should be at least safe.
+	 */
+	rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
+			CPM_DATAONLY_SIZE);
+}
+
+/* This function returns an index into the DPRAM area.
+ */
+uint cpm_dpalloc(uint size, uint align)
+{
+	void *start;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpm_dpmem_lock, flags);
+	cpm_dpmem_info.alignment = align;
+	start = rh_alloc(&cpm_dpmem_info, size, "commproc");
+	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+	return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc);
+
+int cpm_dpfree(uint offset)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpm_dpmem_lock, flags);
+	ret = rh_free(&cpm_dpmem_info, (void *)offset);
+	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(cpm_dpfree);
+
+/* not sure if this is ever needed */
+uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+{
+	void *start;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cpm_dpmem_lock, flags);
+	cpm_dpmem_info.alignment = align;
+	start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+	return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc_fixed);
+
+void cpm_dpdump(void)
+{
+	rh_dump(&cpm_dpmem_info);
+}
+EXPORT_SYMBOL(cpm_dpdump);
+
+void *cpm_dpram_addr(uint offset)
+{
+	return (void *)&cpm2_immr->im_dprambase[offset];
+}
+EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
new file mode 100644
index 0000000..e0db594
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -0,0 +1,181 @@
+/* The CPM2 internal interrupt controller.  It is usually
+ * the only interrupt controller.
+ * There are two 32-bit registers (high/low) for up to 64
+ * possible interrupts.
+ *
+ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
+ * in a simple arithmetic fashion to mask or pending registers.
+ * That is, interrupt 4 does not map to bit position 4.
+ * We create two tables, indexed by vector number, to indicate
+ * which register to use and which bit in the register to use.
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+
+#include <asm/immap_cpm2.h>
+#include <asm/mpc8260.h>
+#include <asm/io.h>
+
+#include "cpm2_pic.h"
+
+static	u_char	irq_to_siureg[] = {
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* bit numbers do not match the docs, these are precomputed so the bit for
+ * a given irq is (1 << irq_to_siubit[irq]) */
+static	u_char	irq_to_siubit[] = {
+	 0, 15, 14, 13, 12, 11, 10,  9,
+	 8,  7,  6,  5,  4,  3,  2,  1,
+	 2,  1,  0, 14, 13, 12, 11, 10,
+	 9,  8,  7,  6,  5,  4,  3,  0,
+	31, 30, 29, 28, 27, 26, 25, 24,
+	23, 22, 21, 20, 19, 18, 17, 16,
+	16, 17, 18, 19, 20, 21, 22, 23,
+	24, 25, 26, 27, 28, 29, 30, 31,
+};
+
+static void cpm2_mask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	irq_nr -= CPM_IRQ_OFFSET;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(cpm2_immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] &= ~(1 << bit);
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void cpm2_unmask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	irq_nr -= CPM_IRQ_OFFSET;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(cpm2_immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] |= 1 << bit;
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void cpm2_mask_and_ack(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr, *sipnr;
+
+	irq_nr -= CPM_IRQ_OFFSET;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(cpm2_immr->im_intctl.ic_simrh);
+	sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
+	ppc_cached_irq_mask[word] &= ~(1 << bit);
+	simr[word] = ppc_cached_irq_mask[word];
+	sipnr[word] = 1 << bit;
+}
+
+static void cpm2_end_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+			&& irq_desc[irq_nr].action) {
+
+		irq_nr -= CPM_IRQ_OFFSET;
+		bit = irq_to_siubit[irq_nr];
+		word = irq_to_siureg[irq_nr];
+
+		simr = &(cpm2_immr->im_intctl.ic_simrh);
+		ppc_cached_irq_mask[word] |= 1 << bit;
+		simr[word] = ppc_cached_irq_mask[word];
+		/*
+		 * Work around large numbers of spurious IRQs on PowerPC 82xx
+		 * systems.
+		 */
+		mb();
+	}
+}
+
+static struct hw_interrupt_type cpm2_pic = {
+	.typename = " CPM2 SIU ",
+	.enable = cpm2_unmask_irq,
+	.disable = cpm2_mask_irq,
+	.ack = cpm2_mask_and_ack,
+	.end = cpm2_end_irq,
+};
+
+int cpm2_get_irq(struct pt_regs *regs)
+{
+	int irq;
+        unsigned long bits;
+
+        /* For CPM2, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = cpm2_immr->im_intctl.ic_sivec;
+        irq = bits >> 26;
+
+	if (irq == 0)
+		return(-1);
+	return irq+CPM_IRQ_OFFSET;
+}
+
+void cpm2_init_IRQ(void)
+{
+	int i;
+	u32 addr;
+
+	/* Clear the CPM IRQ controller, in case it has any bits set
+	 * from the bootloader
+	 */
+
+	/* Mask out everything */
+
+	cpm2_immr->im_intctl.ic_simrh = 0x00000000;
+	cpm2_immr->im_intctl.ic_simrl = 0x00000000;
+
+	wmb();
+
+	/* Ack everything */
+	cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
+	cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
+	wmb();
+
+	/* Dummy read of the vector */
+	i = cpm2_immr->im_intctl.ic_sivec;
+	rmb();
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	cpm2_immr->im_intctl.ic_sicr = 0;
+	cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
+	cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
+
+
+	/* Enable chaining to OpenPIC, and make everything level
+	 */
+	for (i = 0; i < NR_CPM_INTS; i++) {
+		irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
+		irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
+	}
+}
diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h
new file mode 100644
index 0000000..97cab8f
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_pic.h
@@ -0,0 +1,8 @@
+#ifndef _PPC_KERNEL_CPM2_H
+#define _PPC_KERNEL_CPM2_H
+
+extern int cpm2_get_irq(struct pt_regs *regs);
+
+extern void cpm2_init_IRQ(void);
+
+#endif /* _PPC_KERNEL_CPM2_H */
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index ceb5846..bab202d 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -21,6 +21,8 @@ #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
+#include <linux/fs_enet_pd.h>
+#include <linux/fs_uart_pd.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -30,6 +32,10 @@ #include <asm/prom.h>
 #include <sysdev/fsl_soc.h>
 #include <mm/mmu_decl.h>
 
+#ifdef CONFIG_CPM2
+#include <asm/cpm2.h>
+#endif
+
 static phys_addr_t immrbase = -1;
 
 phys_addr_t get_immrbase(void)
@@ -43,7 +49,9 @@ phys_addr_t get_immrbase(void)
 	if (soc) {
 		unsigned int size;
 		void *prop = get_property(soc, "reg", &size);
-		immrbase = of_translate_address(soc, prop);
+
+		if (prop)
+			immrbase = of_translate_address(soc, prop);
 		of_node_put(soc);
 	};
 
@@ -51,7 +59,79 @@ phys_addr_t get_immrbase(void)
 }
 
 EXPORT_SYMBOL(get_immrbase);
+
+static u32 brgfreq = -1;
+
+u32 get_brgfreq(void)
+{
+	struct device_node *node;
+
+	if (brgfreq != -1)
+		return brgfreq;
+
+	node = of_find_node_by_type(NULL, "serial");
+	if (node) {
+		unsigned int size;
+		unsigned int *prop = (unsigned int*)get_property(node, "clock-frequency", &size);
+
+		if (prop)
+			brgfreq = *prop;
+		of_node_put(node);
+	};
+
+	return brgfreq;
+}
+
+EXPORT_SYMBOL(get_brgfreq);
+
+static u32 fs_baudrate = -1;
+
+u32 get_baudrate(void)
+{
+	struct device_node *node;
 
+	if (fs_baudrate != -1)
+		return fs_baudrate;
+
+	node = of_find_node_by_type(NULL, "serial");
+	if (node) {
+		unsigned int size;
+		unsigned int *prop = (unsigned int*)get_property(node, "current-speed", &size);
+
+		if (prop)
+			fs_baudrate = *prop;
+		of_node_put(node);
+	};
+
+	return fs_baudrate;
+}
+
+EXPORT_SYMBOL(get_baudrate);
+
+static u32 intfreq = -1;
+
+u32 get_intfreq(void)
+{
+	struct device_node *node;
+
+	if (intfreq != -1)
+		return intfreq;
+
+	node = of_find_node_by_type(NULL, "cpu");
+	if (node) {
+		unsigned int size;
+		unsigned int *prop = (unsigned int*)get_property(node, "clock-frequency", &size);
+		if (prop)
+			intfreq = *prop;
+		of_node_put(node);
+	}
+
+	return intfreq;
+}
+
+EXPORT_SYMBOL(get_intfreq);
+
+
 static int __init gfar_mdio_of_init(void)
 {
 	struct device_node *np;
@@ -491,3 +571,211 @@ err:
 }
 
 arch_initcall(fsl_usb_dr_of_init);
+
+static const char *fcc_regs = "fcc_regs";
+static const char *fcc_regs_c = "fcc_regs_c";
+static const char *fcc_pram = "fcc_pram";
+static char bus_id[9][BUS_ID_SIZE];
+
+static int __init fs_enet_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *fs_enet_dev;
+	struct resource res;
+	int ret;
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
+	     i++) {
+		struct resource r[4];
+		struct device_node *phy, *mdio;
+		struct fs_platform_info fs_enet_data;
+		unsigned int *id, *phy_addr;
+		void *mac_addr;
+		phandle *ph;
+		char *model;
+
+		memset(r, 0, sizeof(r));
+		memset(&fs_enet_data, 0, sizeof(fs_enet_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+		r[0].name = fcc_regs;
+
+		ret = of_address_to_resource(np, 1, &r[1]);
+		if (ret)
+			goto err;
+		r[1].name = fcc_pram;
+
+		ret = of_address_to_resource(np, 2, &r[2]);
+		if (ret)
+			goto err;
+		r[2].name = fcc_regs_c;
+
+		r[3].start = np->intrs[0].line;
+		r[3].end = np->intrs[0].line;
+		r[3].flags = IORESOURCE_IRQ;
+
+		fs_enet_dev =
+		    platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
+
+		if (IS_ERR(fs_enet_dev)) {
+			ret = PTR_ERR(fs_enet_dev);
+			goto err;
+		}
+
+		model = get_property(np, "model", NULL);
+		if (model == NULL) {
+			ret = -ENODEV;
+			goto unreg;
+		}
+
+		mac_addr = get_property(np, "mac-address", NULL);
+		memcpy(fs_enet_data.macaddr, mac_addr, 6);
+
+		ph = (phandle *) get_property(np, "phy-handle", NULL);
+		phy = of_find_node_by_phandle(*ph);
+
+		if (phy == NULL) {
+			ret = -ENODEV;
+			goto unreg;
+		}
+
+		phy_addr = (u32 *) get_property(phy, "reg", NULL);
+		fs_enet_data.phy_addr = *phy_addr;
+
+		id = (u32 *) get_property(np, "device-id", NULL);
+		fs_enet_data.fs_no = *id;
+
+		mdio = of_get_parent(phy);
+                ret = of_address_to_resource(mdio, 0, &res);
+                if (ret) {
+                        of_node_put(phy);
+                        of_node_put(mdio);
+                        goto unreg;
+                }
+
+		switch (*id) {
+		case fsid_fcc1:
+			fs_enet_data.mem_offset = FCC1_MEM_OFFSET,
+			snprintf((char*)&bus_id[2], BUS_ID_SIZE, "%x:%02x", (u32)res.start, fs_enet_data.phy_addr);
+			fs_enet_data.bus_id = (char*)&bus_id[2];
+			fs_enet_data.cp_page = CPM_CR_FCC1_PAGE;
+			fs_enet_data.cp_block = CPM_CR_FCC1_SBLOCK;
+			break;
+		case fsid_fcc2:
+			fs_enet_data.mem_offset = FCC2_MEM_OFFSET,
+			snprintf((char*)&bus_id[3], BUS_ID_SIZE, "%x:%02x", (u32)res.start, fs_enet_data.phy_addr);
+			fs_enet_data.bus_id = (char*)&bus_id[3];
+			fs_enet_data.cp_page = CPM_CR_FCC2_PAGE;
+			fs_enet_data.cp_block = CPM_CR_FCC2_SBLOCK;
+			break;
+		case fsid_fcc3:
+			fs_enet_data.mem_offset = FCC3_MEM_OFFSET,
+			snprintf((char*)&bus_id[4], BUS_ID_SIZE, "%x:%02x", (u32)res.start, fs_enet_data.phy_addr);
+			fs_enet_data.bus_id = (char*)&bus_id[4];
+			fs_enet_data.cp_page = CPM_CR_FCC3_PAGE;
+			fs_enet_data.cp_block = CPM_CR_FCC3_SBLOCK;
+			break;
+		}
+
+		if (strstr(model, "FCC")) {
+			fs_enet_data.dpram_offset = (u32)cpm2_immr->im_dprambase;
+			fs_enet_data.rx_ring = 32;
+			fs_enet_data.tx_ring = 32;
+			fs_enet_data.rx_copybreak = 240;
+			fs_enet_data.use_napi = 0;
+			fs_enet_data.napi_weight = 17;
+		}
+
+		of_node_put(phy);
+		of_node_put(mdio);
+
+		ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
+					     sizeof(struct
+						    fs_platform_info));
+		if (ret)
+			goto unreg;
+	}
+	return 0;
+
+unreg:
+	platform_device_unregister(fs_enet_dev);
+err:
+	return ret;
+}
+
+arch_initcall(fs_enet_of_init);
+
+static const char *scc_regs = "regs";
+static const char *scc_pram = "pram";
+
+static int __init cpm_uart_of_init(void)
+{
+	struct device_node *np;
+	unsigned int i;
+	struct platform_device *cpm_uart_dev;
+	int ret;
+
+
+	for (np = NULL, i = 0;
+	     (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
+	     i++) {
+		struct resource r[3];
+		struct fs_uart_platform_info cpm_uart_data;
+		int *id;
+
+		memset(r, 0, sizeof(r));
+		memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
+
+		ret = of_address_to_resource(np, 0, &r[0]);
+		if (ret)
+			goto err;
+
+		r[0].name = scc_regs;
+
+		ret = of_address_to_resource(np, 1, &r[1]);
+		if (ret)
+			goto err;
+		r[1].name = scc_pram;
+
+		r[2].start = np->intrs[0].line;
+		r[2].end = np->intrs[0].line;
+		r[2].flags = IORESOURCE_IRQ;
+
+		cpm_uart_dev =
+		    platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3);
+
+		if (IS_ERR(cpm_uart_dev)) {
+			ret = PTR_ERR(cpm_uart_dev);
+			goto err;
+		}
+
+		id = get_property(np, "device-id", NULL);
+		cpm_uart_data.fs_no = *id;
+		cpm_uart_data.uart_clk = get_intfreq();
+
+		cpm_uart_data.tx_num_fifo = 4;
+		cpm_uart_data.tx_buf_size = 32;
+		cpm_uart_data.rx_num_fifo = 4;
+		cpm_uart_data.rx_buf_size = 32;
+
+		ret =
+		    platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
+					     sizeof(struct
+						    fs_uart_platform_info));
+		if (ret)
+			goto unreg;
+	}
+
+	return 0;
+
+unreg:
+	platform_device_unregister(cpm_uart_dev);
+err:
+	return ret;
+}
+
+arch_initcall(cpm_uart_of_init);
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
index f6a7ff0..8e6840b 100644
--- a/include/asm-ppc/cpm2.h
+++ b/include/asm-ppc/cpm2.h
@@ -1186,7 +1186,7 @@ #define PC3_DIRC1	(PC3_TXDAT)
 #define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
 #define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
 #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
-#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
+#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
 
 #endif /* __CPM2__ */
 #endif /* __KERNEL__ */

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/6] CPM_UART: unify clock sources
  2006-06-23 23:17 ` [PATCH 5/6] CPM_UART: unify clock sources Vitaly Bordug
@ 2006-06-24 13:46   ` Kumar Gala
  2006-06-24 15:21     ` Vitaly Bordug
  0 siblings, 1 reply; 14+ messages in thread
From: Kumar Gala @ 2006-06-24 13:46 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev


On Jun 23, 2006, at 6:17 PM, Vitaly Bordug wrote:

>
> In order to make it possible to utilize the driver from arch/ 
> powerpc yet not
> breaking existing ppc users, clock sources are unfied via macro, and
> resources ioremapped.
>
> Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
> ---
>
>  drivers/serial/cpm_uart/cpm_uart_core.c |   11 ++++-------
>  drivers/serial/cpm_uart/cpm_uart_cpm2.c |   13 +++++++------
>  include/asm-powerpc/fs_pd.h             |   17 +++++++++++++++++
>  include/asm-ppc/fs_pd.h                 |   17 +++++++++++++++++
>  4 files changed, 45 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/ 
> serial/cpm_uart/cpm_uart_core.c
> index 5cba59a..0507f74 100644
> --- a/drivers/serial/cpm_uart/cpm_uart_core.c
> +++ b/drivers/serial/cpm_uart/cpm_uart_core.c
> @@ -47,6 +47,7 @@ #include <linux/fs_uart_pd.h>
>  #include <asm/io.h>
>  #include <asm/irq.h>
>  #include <asm/delay.h>
> +#include <asm/fs_pd.h>
>
>  #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
>  #define SUPPORT_SYSRQ
> @@ -1045,11 +1046,11 @@ int cpm_uart_drv_get_platform_data(struc
>
>  	if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM,  
> "regs")))
>  		return -EINVAL;
> -	mem = r->start;
> +	mem = ioremap(r->start, r->end - r->start + 1);
>
>  	if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM,  
> "pram")))
>  		return -EINVAL;
> -	pram = r->start;
> +	pram = ioremap(r->start, r->end - r->start + 1);
>
>  	if(idx > fsid_smc2_uart) {
>  		pinfo->sccp = (scc_t *)mem;
> @@ -1190,11 +1191,7 @@ static int __init cpm_uart_console_setup
>  	if (options) {
>  		uart_parse_options(options, &baud, &parity, &bits, &flow);
>  	} else {
> -		bd_t *bd = (bd_t *) __res;
> -
> -		if (bd->bi_baudrate)
> -			baud = bd->bi_baudrate;
> -		else
> +		if ((baud = GET_BAUDRATE()) == -1)
>  			baud = 9600;
>  	}
>
> diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/ 
> serial/cpm_uart/cpm_uart_cpm2.c
> index cdba128..29b89f0 100644
> --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
> +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
> @@ -41,6 +41,7 @@ #include <linux/dma-mapping.h>
>
>  #include <asm/io.h>
>  #include <asm/irq.h>
> +#include <asm/fs_pd.h>
>
>  #include <linux/serial_core.h>
>  #include <linux/kernel.h>
> @@ -267,7 +268,7 @@ #ifdef CONFIG_SERIAL_CPM_SMC1
>  	    (unsigned long)&cpm2_immr->im_smc[0];
>  	cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
>  	cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN |  
> SMCMR_TEN);
> -	cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)- 
> >bi_intfreq);
> +	cpm_uart_ports[UART_SMC1].port.uartclk = FS_UART_CLK();
>  	cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
>  #endif
>
> @@ -280,7 +281,7 @@ #ifdef CONFIG_SERIAL_CPM_SMC2
>  	    (unsigned long)&cpm2_immr->im_smc[1];
>  	cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
>  	cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN |  
> SMCMR_TEN);
> -	cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)- 
> >bi_intfreq);
> +	cpm_uart_ports[UART_SMC2].port.uartclk = FS_UART_CLK();
>  	cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
>  #endif
>
> @@ -294,7 +295,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC1
>  	    ~(UART_SCCM_TX | UART_SCCM_RX);
>  	cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
>  	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
> -	cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)- 
> >bi_intfreq);
> +	cpm_uart_ports[UART_SCC1].port.uartclk = FS_UART_CLK();
>  	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
>  #endif
>
> @@ -308,7 +309,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC2
>  	    ~(UART_SCCM_TX | UART_SCCM_RX);
>  	cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
>  	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
> -	cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)- 
> >bi_intfreq);
> +	cpm_uart_ports[UART_SCC2].port.uartclk = FS_UART_CLK();
>  	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
>  #endif
>
> @@ -322,7 +323,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC3
>  	    ~(UART_SCCM_TX | UART_SCCM_RX);
>  	cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
>  	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
> -	cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)- 
> >bi_intfreq);
> +	cpm_uart_ports[UART_SCC3].port.uartclk = FS_UART_CLK();
>  	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
>  #endif
>
> @@ -336,7 +337,7 @@ #ifdef CONFIG_SERIAL_CPM_SCC4
>  	    ~(UART_SCCM_TX | UART_SCCM_RX);
>  	cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
>  	    ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
> -	cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)- 
> >bi_intfreq);
> +	cpm_uart_ports[UART_SCC4].port.uartclk = FS_UART_CLK();
>  	cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
>  #endif
>
> diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h
> new file mode 100644
> index 0000000..b20d8da
> --- /dev/null
> +++ b/include/asm-powerpc/fs_pd.h
> @@ -0,0 +1,17 @@
> +/*
> + * Platform information definitions.
> + *
> + * 2006 (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 FS_PD_H
> +#define FS_PD_H
> +
> +#define GET_BAUDRATE()	get_baudrate()
> +#define FS_UART_CLK()	get_intfreq()
> +
> +#endif
> diff --git a/include/asm-ppc/fs_pd.h b/include/asm-ppc/fs_pd.h
> new file mode 100644
> index 0000000..b1d550b
> --- /dev/null
> +++ b/include/asm-ppc/fs_pd.h
> @@ -0,0 +1,17 @@
> +/*
> + * Platform information definitions.
> + *
> + * 2006 (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 FS_PD_H
> +#define FS_PD_H
> +
> +#define GET_BAUDRATE()	(((bd_t *) __res)->bi_baudrate ? ((bd_t *)  
> __res)->bi_baudrate : -1)
> +#define FS_UART_CLK()	(((bd_t *) __res)->bi_intfreq)
> +
> +#endif

We shouldn't hide these differences in a header like this.  As we  
slowly try to removing things from arch/ppc.  Why not just add  
platform data for these two pieces of data and set it up like we do  
other platform data.

- k

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/6] CPM_UART: unify clock sources
  2006-06-24 13:46   ` Kumar Gala
@ 2006-06-24 15:21     ` Vitaly Bordug
  2006-06-24 15:50       ` Kumar Gala
  2006-06-24 16:22       ` Jon Loeliger
  0 siblings, 2 replies; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-24 15:21 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev

Kumar, 

Thanks for feedback! My comment below.

On Sat, 24 Jun 2006 08:46:54 -0500
Kumar Gala <galak@kernel.crashing.org> wrote:

[snip]
> > +
> > +#ifndef FS_PD_H
> > +#define FS_PD_H
> > +
> > +#define GET_BAUDRATE()	(((bd_t *) __res)->bi_baudrate ?
> > ((bd_t *) __res)->bi_baudrate : -1)
> > +#define FS_UART_CLK()	(((bd_t *) __res)->bi_intfreq)
> > +
> > +#endif
> 
> We shouldn't hide these differences in a header like this.  As we  
> slowly try to removing things from arch/ppc.  Why not just add  
> platform data for these two pieces of data and set it up like we do  
> other platform data.
> 
That was my first guess as well, but: 
The aim is yet moving to powerpc not to break existing ppc/ stuff. 
So if alternatively platform_data may be utilized, all relevant ppc
stuff that uses cpm uart should be updated. While doing the driver
"platformize" trick, I made it possible to keep legacy behaviour
(pd-less), this is not going to afford such a thing. 

IOW, I don't see much sense in updating ppc/ BSP files, just to keep
the right way. It does not look very neat now, but does the job of
moving FW and keeping existing stuff sane. If there is better approach
envisioned, I'll definitely follow..

--
Sincerely, Vitaly

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/6] CPM_UART: unify clock sources
  2006-06-24 15:21     ` Vitaly Bordug
@ 2006-06-24 15:50       ` Kumar Gala
  2006-06-24 16:22       ` Jon Loeliger
  1 sibling, 0 replies; 14+ messages in thread
From: Kumar Gala @ 2006-06-24 15:50 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev


On Jun 24, 2006, at 10:21 AM, Vitaly Bordug wrote:

> Kumar,
>
> Thanks for feedback! My comment below.
>
> On Sat, 24 Jun 2006 08:46:54 -0500
> Kumar Gala <galak@kernel.crashing.org> wrote:
>
> [snip]
>>> +
>>> +#ifndef FS_PD_H
>>> +#define FS_PD_H
>>> +
>>> +#define GET_BAUDRATE()	(((bd_t *) __res)->bi_baudrate ?
>>> ((bd_t *) __res)->bi_baudrate : -1)
>>> +#define FS_UART_CLK()	(((bd_t *) __res)->bi_intfreq)
>>> +
>>> +#endif
>>
>> We shouldn't hide these differences in a header like this.  As we
>> slowly try to removing things from arch/ppc.  Why not just add
>> platform data for these two pieces of data and set it up like we do
>> other platform data.
>>
> That was my first guess as well, but:
> The aim is yet moving to powerpc not to break existing ppc/ stuff.
> So if alternatively platform_data may be utilized, all relevant ppc
> stuff that uses cpm uart should be updated. While doing the driver
> "platformize" trick, I made it possible to keep legacy behaviour
> (pd-less), this is not going to afford such a thing.
>
> IOW, I don't see much sense in updating ppc/ BSP files, just to keep
> the right way. It does not look very neat now, but does the job of
> moving FW and keeping existing stuff sane. If there is better approach
> envisioned, I'll definitely follow..

Fair enough, then I would suggest getting ride of all this header/ 
MACRO indirection and just implement these as functions with  
different implementations in arch/powerpc vs arch/ppc.

- k

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/6] CPM_UART: unify clock sources
  2006-06-24 15:21     ` Vitaly Bordug
  2006-06-24 15:50       ` Kumar Gala
@ 2006-06-24 16:22       ` Jon Loeliger
  2006-06-24 16:27         ` Kumar Gala
  1 sibling, 1 reply; 14+ messages in thread
From: Jon Loeliger @ 2006-06-24 16:22 UTC (permalink / raw)
  To: linuxppc-dev

So, like, the other day Vitaly Bordug mumbled:
> That was my first guess as well, but: 
> The aim is yet moving to powerpc not to break existing ppc/ stuff. 
> So if alternatively platform_data may be utilized, all relevant ppc
> stuff that uses cpm uart should be updated. While doing the driver
> "platformize" trick, I made it possible to keep legacy behaviour
> (pd-less), this is not going to afford such a thing. 
> 
> IOW, I don't see much sense in updating ppc/ BSP files, just to keep
> the right way. It does not look very neat now, but does the job of
> moving FW and keeping existing stuff sane. If there is better approach
> envisioned, I'll definitely follow..

And don't forget that the subsequent, follow-up patches
will be to _remove_ the 85xx family from arch/ppc as well.
The trick right now is simply to get it working in arch/powerpc
so that we can move forward there.  Worrying about absolute
cleanliness in arch/ppc for 85xx shouldn't, in my opinion,
be the highest concern.

Thanks,
jdl

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support
  2006-06-23 23:17 ` [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support Vitaly Bordug
@ 2006-06-24 16:26   ` Kumar Gala
  2006-06-24 17:17     ` Vitaly Bordug
  0 siblings, 1 reply; 14+ messages in thread
From: Kumar Gala @ 2006-06-24 16:26 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev


On Jun 23, 2006, at 6:17 PM, Vitaly Bordug wrote:

>
> This enables the mpc8560-specific bits in powerpc. The relevant  
> cpm2 PIC
> and common utility were moved without or with minor changes, hereby  
> not all
> the stuff have OF power utilized. Current functionality depends on  
> the very
> latest fs_enet update, that will go through netdev (cc'd here as
> reference). Assuming all the preceeding stuff applied (PAL+fs_enet  
> related
> + CPM_UART update), the both TSEC eth ,FCC Eths, and both SCC UARTs  
> are
> working. The relevant drivers are still capable to drive users in ppc,
> which was verified with 8272ADS (SCC uart+FCC eth).
>
> Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>

Can you break this patch up into its pieces (moving of cpm2* files),  
fsl_soc mods, 8560 additions.

> ---
>
>  arch/powerpc/lib/Makefile                 |    5 +
>  arch/powerpc/platforms/85xx/Kconfig       |   11 +
>  arch/powerpc/platforms/85xx/Makefile      |    1
>  arch/powerpc/platforms/85xx/mpc8560_ads.h |   54 +++++
>  arch/powerpc/platforms/85xx/mpc85xx_ads.c |  107 +++++++++++
>  arch/powerpc/sysdev/Makefile              |    7 +
>  arch/powerpc/sysdev/cpm2_common.c         |  197 ++++++++++++++++++++
>  arch/powerpc/sysdev/cpm2_pic.c            |  181 ++++++++++++++++++
>  arch/powerpc/sysdev/cpm2_pic.h            |    8 +
>  arch/powerpc/sysdev/fsl_soc.c             |  290 ++++++++++++++++++ 
> +++++++++++
>  include/asm-ppc/cpm2.h                    |    2
>  11 files changed, 860 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
> index ff70964..0993b3b 100644
> --- a/arch/powerpc/lib/Makefile
> +++ b/arch/powerpc/lib/Makefile
> @@ -21,3 +21,8 @@ ifeq ($(CONFIG_PPC64),y)
>  obj-$(CONFIG_SMP)	+= locks.o
>  obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
>  endif
> +
> +# Temporary hack until we have migrated to asm-powerpc
> +ifeq ($(ARCH),powerpc)
> +obj-$(CONFIG_CPM2)	+= rheap.o
> +endif

Why not just move the file and build in arch/powerpc/lib/ for both  
arch/powerpc & arch/ppc.  Same goes for cpm_* files.

> diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/ 
> platforms/85xx/Kconfig
> index 454fc53..3d440de 100644
> --- a/arch/powerpc/platforms/85xx/Kconfig
> +++ b/arch/powerpc/platforms/85xx/Kconfig
> @@ -11,6 +11,12 @@ config MPC8540_ADS
>  	help
>  	  This option enables support for the MPC 8540 ADS board
>
> +config MPC8560_ADS
> +	bool "Freescale MPC8560 ADS"
> +	select DEFAULT_UIMAGE
> +	help
> +	  This option enables support for the MPC 8560 ADS board
> +
>  config MPC85xx_CDS
>  	bool "Freescale MPC85xx CDS"
>  	select DEFAULT_UIMAGE
> @@ -25,6 +31,11 @@ config MPC8540
>  	select PPC_UDBG_16550
>  	select PPC_INDIRECT_PCI
>  	default y if MPC8540_ADS || MPC85xx_CDS
> +
> +config MPC8560
> +	bool
> +	select PPC_INDIRECT_PCI
> +	default y if MPC8560_ADS
>
>  config PPC_INDIRECT_PCI_BE
>  	bool
> diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/ 
> platforms/85xx/Makefile
> index 7615aa5..282f5d0 100644
> --- a/arch/powerpc/platforms/85xx/Makefile
> +++ b/arch/powerpc/platforms/85xx/Makefile
> @@ -3,4 +3,5 @@ # Makefile for the PowerPC 85xx linux ke
>  #
>  obj-$(CONFIG_PPC_85xx)	+= misc.o pci.o
>  obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
> +obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
>  obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
> diff --git a/arch/powerpc/platforms/85xx/mpc8560_ads.h b/arch/ 
> powerpc/platforms/85xx/mpc8560_ads.h
> new file mode 100644
> index 0000000..4ebe710
> --- /dev/null
> +++ b/arch/powerpc/platforms/85xx/mpc8560_ads.h
> @@ -0,0 +1,54 @@
> +/*
> + * MPC8560ADS board definitions
> + *
> + * Maintainer: Kumar Gala <galak@kernel.crashing.org>
> + *
> + * Copyright 2004 Freescale Semiconductor Inc.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __MACH_MPC8560ADS_H
> +#define __MACH_MPC8560ADS_H
> +
> +#include <linux/config.h>
> +#include <linux/initrd.h>
> +
> +#define BOARD_CCSRBAR		((uint)0xe0000000)
> +#define BCSR_ADDR		((uint)0xf8000000)
> +#define BCSR_SIZE		((uint)(32 * 1024))
> +
> +#define MPC85xx_CPM_OFFSET	(0x80000)
> +
> +/*XXX TODO: pull from OF*/
> +#define CPM_MAP_ADDR		(BOARD_CCSRBAR + MPC85xx_CPM_OFFSET)
> +
> +/* PCI interrupt controller */
> +#define PIRQA		MPC85xx_IRQ_EXT1
> +#define PIRQB		MPC85xx_IRQ_EXT2
> +#define PIRQC		MPC85xx_IRQ_EXT3
> +#define PIRQD		MPC85xx_IRQ_EXT4
> +
> +/* FCC1 Clock Source Configuration.  These can be
> + * redefined in the board specific file.
> + *    Can only choose from CLK9-12 */
> +#define F1_RXCLK       12
> +#define F1_TXCLK       11
> +
> +/* FCC2 Clock Source Configuration.  These can be
> + * redefined in the board specific file.
> + *    Can only choose from CLK13-16 */
> +#define F2_RXCLK       13
> +#define F2_TXCLK       14
> +
> +/* FCC3 Clock Source Configuration.  These can be
> + * redefined in the board specific file.
> + *    Can only choose from CLK13-16 */
> +#define F3_RXCLK       15
> +#define F3_TXCLK       16
> +
> +#endif				/* __MACH_MPC8560ADS_H */
> diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/ 
> powerpc/platforms/85xx/mpc85xx_ads.c
> index 5eeff37..352d0ae 100644
> --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> @@ -15,6 +15,7 @@ #include <linux/config.h>
>  #include <linux/stddef.h>
>  #include <linux/kernel.h>
>  #include <linux/pci.h>
> +#include <linux/interrupt.h>
>  #include <linux/kdev_t.h>
>  #include <linux/delay.h>
>  #include <linux/seq_file.h>
> @@ -30,6 +31,10 @@ #include <asm/mpic.h>
>  #include <mm/mmu_decl.h>
>  #include <asm/udbg.h>
>
> +#ifdef CONFIG_CPM2
> +#include <asm/cpm2.h>
> +#endif
> +
>  #include <sysdev/fsl_soc.h>
>  #include "mpc85xx.h"
>
> @@ -121,8 +126,25 @@ mpc85xx_exclude_device(u_char bus, u_cha
>  }
>
>  #endif /* CONFIG_PCI */
> +
> +#ifdef CONFIG_CPM2
>
> +static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct  
> pt_regs *regs)
> +{
> +	while ((irq = cpm2_get_irq(regs)) >= 0)
> +		__do_IRQ(irq, regs);
> +	return IRQ_HANDLED;
> +}
>
> +static struct irqaction cpm2_irqaction = {
> +	.handler = cpm2_cascade,
> +	.flags = SA_INTERRUPT,
> +	.mask = CPU_MASK_NONE,
> +	.name = "cpm2_cascade",
> +};
> +

I'd prefer that we see Ben's new IRQ support before doing this, but  
ok for now.

> +#endif /* CONFIG_CPM2 */
> +
>  void __init mpc85xx_ads_pic_init(void)
>  {
>  	struct mpic *mpic1;
> @@ -158,15 +180,91 @@ void __init mpc85xx_ads_pic_init(void)
>  	mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
>  	mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
>  	mpic_init(mpic1);
> +
> +#ifdef CONFIG_CPM2
> +	/* Setup CPM2 PIC */
> +
> +        cpm2_init_IRQ();
> +
> +	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
> +#endif
>  }
>
>  /*
>   * Setup the architecture
> - */
> + */
> +static void init_fcc_ioports(void)
> +{
> +	struct immap *immap;
> +	struct io_port *io;
> +	u32 tempval;
> +
> +	immap = cpm2_immr;
> +
> +	io = &immap->im_ioport;
> +	/* FCC2/3 are on the ports B/C. */
> +	tempval = in_be32(&io->iop_pdirb);
> +	tempval &= ~PB2_DIRB0;
> +	tempval |= PB2_DIRB1;
> +	out_be32(&io->iop_pdirb, tempval);
> +
> +	tempval = in_be32(&io->iop_psorb);
> +	tempval &= ~PB2_PSORB0;
> +	tempval |= PB2_PSORB1;
> +	out_be32(&io->iop_psorb, tempval);
> +
> +	tempval = in_be32(&io->iop_pparb);
> +	tempval |= (PB2_DIRB0 | PB2_DIRB1);
> +	out_be32(&io->iop_pparb, tempval);
> +
> +	tempval = in_be32(&io->iop_pdirb);
> +	tempval &= ~PB3_DIRB0;
> +	tempval |= PB3_DIRB1;
> +	out_be32(&io->iop_pdirb, tempval);
> +
> +	tempval = in_be32(&io->iop_psorb);
> +	tempval &= ~PB3_PSORB0;
> +	tempval |= PB3_PSORB1;
> +	out_be32(&io->iop_psorb, tempval);
> +
> +	tempval = in_be32(&io->iop_pparb);
> +	tempval |= (PB3_DIRB0 | PB3_DIRB1);
> +	out_be32(&io->iop_pparb, tempval);
> +
> +	tempval = in_be32(&io->iop_pdirc);
> +	tempval |= PC3_DIRC1;
> +	out_be32(&io->iop_pdirc, tempval);
> +
> +	tempval = in_be32(&io->iop_pparc);
> +	tempval |= PC3_DIRC1;
> +	out_be32(&io->iop_pparc, tempval);
> +
> +	/* Port C has clocks......  */
> +	tempval = in_be32(&io->iop_psorc);
> +	tempval &= ~(CLK_TRX);
> +	out_be32(&io->iop_psorc, tempval);
> +
> +	tempval = in_be32(&io->iop_pdirc);
> +	tempval &= ~(CLK_TRX);
> +	out_be32(&io->iop_pdirc, tempval);
> +	tempval = in_be32(&io->iop_pparc);
> +	tempval |= (CLK_TRX);
> +	out_be32(&io->iop_pparc, tempval);
> +
> +	/* Configure Serial Interface clock routing.
> +	 * First,  clear all FCC bits to zero,
> +	 * then set the ones we want.
> +	 */
> +	immap->im_cpmux.cmx_fcr &= ~(CPMUX_CLK_MASK);
> +	immap->im_cpmux.cmx_fcr |= CPMUX_CLK_ROUTE;
> +}

Can this be turned into some library function that uses some input  
that is board specific.  U-boot has a table that looked like a  
reasonable approach.

> +
>  static void __init mpc85xx_ads_setup_arch(void)
>  {
>  	struct device_node *cpu;
>  	struct device_node *np;
> +
> +	cpm2_reset();
>
>  	if (ppc_md.progress)
>  		ppc_md.progress("mpc85xx_ads_setup_arch()", 0);
> @@ -184,8 +282,13 @@ static void __init mpc85xx_ads_setup_arc
>  	}
>
>  #ifdef CONFIG_PCI
> +
>  	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
>  		add_bridge(np);
> +
> +#ifdef CONFIG_CPM2
> +	init_fcc_ioports();
> +#endif

This appears to be inside the CONFIG_PCI #ifdef, is that really what  
you want?

>  	ppc_md.pci_swizzle = common_swizzle;
>  	ppc_md.pci_map_irq = mpc85xx_map_irq;
> @@ -240,5 +343,7 @@ define_machine(mpc85xx_ads) {
>  	.get_irq		= mpic_get_irq,
>  	.restart		= mpc85xx_restart,
>  	.calibrate_decr		= generic_calibrate_decr,
> +#ifndef CONFIG_CPM2
>  	.progress		= udbg_progress,
> +#endif
>  };
> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/ 
> Makefile
> index cef95b0..75dfe12 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -12,3 +12,10 @@ obj-$(CONFIG_U3_DART)		+= dart_iommu.o
>  obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
>  obj-$(CONFIG_PPC_83xx)		+= ipic.o
>  obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
> +
> +# Temporary hack until we have migrated to asm-powerpc
> +ifeq ($(ARCH),powerpc)
> +obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
> +endif

See earlier comments about just building in arch/powerpc

> +
> +#obj-$(CONFIG_CPM2)		+= cpm2/			Yuri
> diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/ 
> sysdev/cpm2_common.c
> new file mode 100644
> index 0000000..c755f65
> --- /dev/null
> +++ b/arch/powerpc/sysdev/cpm2_common.c
> @@ -0,0 +1,197 @@
> +/*
> + * General Purpose functions for the global management of the
> + * 8260 Communication Processor Module.
> + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
> + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
> + *	2.3.99 Updates
> + *
> + * In addition to the individual control of the communication
> + * channels, there are a few functions that globally affect the
> + * communication processor.
> + *
> + * Buffer descriptors must be allocated from the dual ported memory
> + * space.  The allocator for that is here.  When the communication
> + * process is reset, we reclaim the memory available.  There is
> + * currently no deallocator for this memory.
> + */
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/param.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/mpc8260.h>
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +#include <asm/cpm2.h>
> +#include <asm/rheap.h>
> +
> +static void cpm2_dpinit(void);
> +cpm_cpm2_t	*cpmp;		/* Pointer to comm processor space */
> +
> +/* We allocate this here because it is used almost exclusively for
> + * the communication processor devices.
> + */
> +cpm2_map_t *cpm2_immr;
> +
> +#define CPM_MAP_SIZE	(0x40000)	/* 256k - the PQ3 reserve this amount
> +					   of space for CPM as it is larger
> +					   than on PQ2 */
> +
> +void
> +cpm2_reset(void)
> +{
> +	cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);

You dont need the cast.

> +
> +	/* Reclaim the DP memory for our use.
> +	 */
> +	cpm2_dpinit();
> +
> +	/* Tell everyone where the comm processor resides.
> +	 */
> +	cpmp = &cpm2_immr->im_cpm;
> +}
> +
> +/* Set a baud rate generator.  This needs lots of work.  There are
> + * eight BRGs, which can be connected to the CPM channels or output
> + * as clocks.  The BRGs are in two different block of internal
> + * memory mapped space.
> + * The baud rate clock is the system clock divided by something.
> + * It was set up long ago during the initial boot phase and is
> + * is given to us.
> + * Baud rate clocks are zero-based in the driver code (as that maps
> + * to port numbers).  Documentation uses 1-based numbering.
> + */
> +#define BRG_INT_CLK	(get_brgfreq())
> +#define BRG_UART_CLK	(BRG_INT_CLK/16)
> +
> +/* This function is used by UARTS, or anything else that uses a 16x
> + * oversampled clock.
> + */
> +void
> +cpm_setbrg(uint brg, uint rate)
> +{
> +	volatile uint	*bp;
> +
> +	/* This is good enough to get SMCs running.....
> +	*/
> +	if (brg < 4) {
> +		bp = (uint *)&cpm2_immr->im_brgc1;
> +	}
> +	else {
> +		bp = (uint *)&cpm2_immr->im_brgc5;
> +		brg -= 4;
> +	}
> +	bp += brg;
> +	*bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
> +}
> +
> +/* This function is used to set high speed synchronous baud rate
> + * clocks.
> + */
> +void
> +cpm2_fastbrg(uint brg, uint rate, int div16)
> +{
> +	volatile uint	*bp;
> +
> +	if (brg < 4) {
> +		bp = (uint *)&cpm2_immr->im_brgc1;
> +	}
> +	else {
> +		bp = (uint *)&cpm2_immr->im_brgc5;
> +		brg -= 4;
> +	}
> +	bp += brg;
> +	*bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
> +	if (div16)
> +		*bp |= CPM_BRG_DIV16;
> +}
> +
> +/*
> + * dpalloc / dpfree bits.
> + */
> +static spinlock_t cpm_dpmem_lock;
> +/* 16 blocks should be enough to satisfy all requests
> + * until the memory subsystem goes up... */
> +static rh_block_t cpm_boot_dpmem_rh_block[16];
> +static rh_info_t cpm_dpmem_info;
> +
> +static void cpm2_dpinit(void)
> +{
> +	spin_lock_init(&cpm_dpmem_lock);
> +
> +	/* initialize the info header */
> +	rh_init(&cpm_dpmem_info, 1,
> +			sizeof(cpm_boot_dpmem_rh_block) /
> +			sizeof(cpm_boot_dpmem_rh_block[0]),
> +			cpm_boot_dpmem_rh_block);
> +
> +	/* Attach the usable dpmem area */
> +	/* XXX: This is actually crap. CPM_DATAONLY_BASE and
> +	 * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
> +	 * varies with the processor and the microcode patches activated.
> +	 * But the following should be at least safe.
> +	 */
> +	rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
> +			CPM_DATAONLY_SIZE);
> +}
> +
> +/* This function returns an index into the DPRAM area.
> + */
> +uint cpm_dpalloc(uint size, uint align)
> +{
> +	void *start;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&cpm_dpmem_lock, flags);
> +	cpm_dpmem_info.alignment = align;
> +	start = rh_alloc(&cpm_dpmem_info, size, "commproc");
> +	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
> +
> +	return (uint)start;
> +}
> +EXPORT_SYMBOL(cpm_dpalloc);
> +
> +int cpm_dpfree(uint offset)
> +{
> +	int ret;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&cpm_dpmem_lock, flags);
> +	ret = rh_free(&cpm_dpmem_info, (void *)offset);
> +	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(cpm_dpfree);
> +
> +/* not sure if this is ever needed */
> +uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
> +{
> +	void *start;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&cpm_dpmem_lock, flags);
> +	cpm_dpmem_info.alignment = align;
> +	start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size,  
> "commproc");
> +	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
> +
> +	return (uint)start;
> +}
> +EXPORT_SYMBOL(cpm_dpalloc_fixed);
> +
> +void cpm_dpdump(void)
> +{
> +	rh_dump(&cpm_dpmem_info);
> +}
> +EXPORT_SYMBOL(cpm_dpdump);
> +
> +void *cpm_dpram_addr(uint offset)
> +{
> +	return (void *)&cpm2_immr->im_dprambase[offset];
> +}
> +EXPORT_SYMBOL(cpm_dpram_addr);
> diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/ 
> cpm2_pic.c
> new file mode 100644
> index 0000000..e0db594
> --- /dev/null
> +++ b/arch/powerpc/sysdev/cpm2_pic.c
> @@ -0,0 +1,181 @@
> +/* The CPM2 internal interrupt controller.  It is usually
> + * the only interrupt controller.
> + * There are two 32-bit registers (high/low) for up to 64
> + * possible interrupts.
> + *
> + * Now, the fun starts.....Interrupt Numbers DO NOT MAP
> + * in a simple arithmetic fashion to mask or pending registers.
> + * That is, interrupt 4 does not map to bit position 4.
> + * We create two tables, indexed by vector number, to indicate
> + * which register to use and which bit in the register to use.
> + */
> +
> +#include <linux/stddef.h>
> +#include <linux/init.h>
> +#include <linux/sched.h>
> +#include <linux/signal.h>
> +#include <linux/irq.h>
> +
> +#include <asm/immap_cpm2.h>
> +#include <asm/mpc8260.h>
> +#include <asm/io.h>
> +
> +#include "cpm2_pic.h"
> +
> +static	u_char	irq_to_siureg[] = {
> +	1, 1, 1, 1, 1, 1, 1, 1,
> +	1, 1, 1, 1, 1, 1, 1, 1,
> +	0, 0, 0, 0, 0, 0, 0, 0,
> +	0, 0, 0, 0, 0, 0, 0, 0,
> +	1, 1, 1, 1, 1, 1, 1, 1,
> +	1, 1, 1, 1, 1, 1, 1, 1,
> +	0, 0, 0, 0, 0, 0, 0, 0,
> +	0, 0, 0, 0, 0, 0, 0, 0
> +};
> +
> +/* bit numbers do not match the docs, these are precomputed so the  
> bit for
> + * a given irq is (1 << irq_to_siubit[irq]) */
> +static	u_char	irq_to_siubit[] = {
> +	 0, 15, 14, 13, 12, 11, 10,  9,
> +	 8,  7,  6,  5,  4,  3,  2,  1,
> +	 2,  1,  0, 14, 13, 12, 11, 10,
> +	 9,  8,  7,  6,  5,  4,  3,  0,
> +	31, 30, 29, 28, 27, 26, 25, 24,
> +	23, 22, 21, 20, 19, 18, 17, 16,
> +	16, 17, 18, 19, 20, 21, 22, 23,
> +	24, 25, 26, 27, 28, 29, 30, 31,
> +};
> +
> +static void cpm2_mask_irq(unsigned int irq_nr)
> +{
> +	int	bit, word;
> +	volatile uint	*simr;
> +
> +	irq_nr -= CPM_IRQ_OFFSET;
> +
> +	bit = irq_to_siubit[irq_nr];
> +	word = irq_to_siureg[irq_nr];
> +
> +	simr = &(cpm2_immr->im_intctl.ic_simrh);
> +	ppc_cached_irq_mask[word] &= ~(1 << bit);
> +	simr[word] = ppc_cached_irq_mask[word];
> +}
> +
> +static void cpm2_unmask_irq(unsigned int irq_nr)
> +{
> +	int	bit, word;
> +	volatile uint	*simr;
> +
> +	irq_nr -= CPM_IRQ_OFFSET;
> +
> +	bit = irq_to_siubit[irq_nr];
> +	word = irq_to_siureg[irq_nr];
> +
> +	simr = &(cpm2_immr->im_intctl.ic_simrh);
> +	ppc_cached_irq_mask[word] |= 1 << bit;
> +	simr[word] = ppc_cached_irq_mask[word];
> +}
> +
> +static void cpm2_mask_and_ack(unsigned int irq_nr)
> +{
> +	int	bit, word;
> +	volatile uint	*simr, *sipnr;
> +
> +	irq_nr -= CPM_IRQ_OFFSET;
> +
> +	bit = irq_to_siubit[irq_nr];
> +	word = irq_to_siureg[irq_nr];
> +
> +	simr = &(cpm2_immr->im_intctl.ic_simrh);
> +	sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
> +	ppc_cached_irq_mask[word] &= ~(1 << bit);
> +	simr[word] = ppc_cached_irq_mask[word];
> +	sipnr[word] = 1 << bit;
> +}
> +
> +static void cpm2_end_irq(unsigned int irq_nr)
> +{
> +	int	bit, word;
> +	volatile uint	*simr;
> +
> +	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
> +			&& irq_desc[irq_nr].action) {
> +
> +		irq_nr -= CPM_IRQ_OFFSET;
> +		bit = irq_to_siubit[irq_nr];
> +		word = irq_to_siureg[irq_nr];
> +
> +		simr = &(cpm2_immr->im_intctl.ic_simrh);
> +		ppc_cached_irq_mask[word] |= 1 << bit;
> +		simr[word] = ppc_cached_irq_mask[word];
> +		/*
> +		 * Work around large numbers of spurious IRQs on PowerPC 82xx
> +		 * systems.
> +		 */
> +		mb();
> +	}
> +}
> +
> +static struct hw_interrupt_type cpm2_pic = {
> +	.typename = " CPM2 SIU ",
> +	.enable = cpm2_unmask_irq,
> +	.disable = cpm2_mask_irq,
> +	.ack = cpm2_mask_and_ack,
> +	.end = cpm2_end_irq,
> +};
> +
> +int cpm2_get_irq(struct pt_regs *regs)
> +{
> +	int irq;
> +        unsigned long bits;
> +
> +        /* For CPM2, read the SIVEC register and shift the bits down
> +         * to get the irq number.         */
> +        bits = cpm2_immr->im_intctl.ic_sivec;
> +        irq = bits >> 26;
> +
> +	if (irq == 0)
> +		return(-1);
> +	return irq+CPM_IRQ_OFFSET;
> +}
> +
> +void cpm2_init_IRQ(void)
> +{
> +	int i;
> +	u32 addr;
> +
> +	/* Clear the CPM IRQ controller, in case it has any bits set
> +	 * from the bootloader
> +	 */
> +
> +	/* Mask out everything */
> +
> +	cpm2_immr->im_intctl.ic_simrh = 0x00000000;
> +	cpm2_immr->im_intctl.ic_simrl = 0x00000000;
> +
> +	wmb();
> +
> +	/* Ack everything */
> +	cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
> +	cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
> +	wmb();
> +
> +	/* Dummy read of the vector */
> +	i = cpm2_immr->im_intctl.ic_sivec;
> +	rmb();
> +
> +	/* Initialize the default interrupt mapping priorities,
> +	 * in case the boot rom changed something on us.
> +	 */
> +	cpm2_immr->im_intctl.ic_sicr = 0;
> +	cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
> +	cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
> +
> +
> +	/* Enable chaining to OpenPIC, and make everything level
> +	 */
> +	for (i = 0; i < NR_CPM_INTS; i++) {
> +		irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
> +		irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
> +	}
> +}
> diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/ 
> cpm2_pic.h
> new file mode 100644
> index 0000000..97cab8f
> --- /dev/null
> +++ b/arch/powerpc/sysdev/cpm2_pic.h
> @@ -0,0 +1,8 @@
> +#ifndef _PPC_KERNEL_CPM2_H
> +#define _PPC_KERNEL_CPM2_H
> +
> +extern int cpm2_get_irq(struct pt_regs *regs);
> +
> +extern void cpm2_init_IRQ(void);
> +
> +#endif /* _PPC_KERNEL_CPM2_H */
> diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/ 
> fsl_soc.c
> index ceb5846..bab202d 100644
> --- a/arch/powerpc/sysdev/fsl_soc.c
> +++ b/arch/powerpc/sysdev/fsl_soc.c
> @@ -21,6 +21,8 @@ #include <linux/module.h>
>  #include <linux/device.h>
>  #include <linux/platform_device.h>
>  #include <linux/fsl_devices.h>
> +#include <linux/fs_enet_pd.h>
> +#include <linux/fs_uart_pd.h>
>
>  #include <asm/system.h>
>  #include <asm/atomic.h>
> @@ -30,6 +32,10 @@ #include <asm/prom.h>
>  #include <sysdev/fsl_soc.h>
>  #include <mm/mmu_decl.h>
>
> +#ifdef CONFIG_CPM2
> +#include <asm/cpm2.h>
> +#endif
> +
>  static phys_addr_t immrbase = -1;
>
>  phys_addr_t get_immrbase(void)
> @@ -43,7 +49,9 @@ phys_addr_t get_immrbase(void)
>  	if (soc) {
>  		unsigned int size;
>  		void *prop = get_property(soc, "reg", &size);
> -		immrbase = of_translate_address(soc, prop);
> +
> +		if (prop)
> +			immrbase = of_translate_address(soc, prop);
>  		of_node_put(soc);
>  	};
>
> @@ -51,7 +59,79 @@ phys_addr_t get_immrbase(void)
>  }
>
>  EXPORT_SYMBOL(get_immrbase);
> +
> +static u32 brgfreq = -1;
> +
> +u32 get_brgfreq(void)
> +{
> +	struct device_node *node;
> +
> +	if (brgfreq != -1)
> +		return brgfreq;
> +
> +	node = of_find_node_by_type(NULL, "serial");
> +	if (node) {
> +		unsigned int size;
> +		unsigned int *prop = (unsigned int*)get_property(node, "clock- 
> frequency", &size);
> +
> +		if (prop)
> +			brgfreq = *prop;
> +		of_node_put(node);
> +	};
> +
> +	return brgfreq;
> +}

These seems broken on a system w/both CPM & 8250 style uarts.

> +
> +EXPORT_SYMBOL(get_brgfreq);
> +
> +static u32 fs_baudrate = -1;
> +
> +u32 get_baudrate(void)
> +{
> +	struct device_node *node;
>
> +	if (fs_baudrate != -1)
> +		return fs_baudrate;
> +
> +	node = of_find_node_by_type(NULL, "serial");
> +	if (node) {
> +		unsigned int size;
> +		unsigned int *prop = (unsigned int*)get_property(node, "current- 
> speed", &size);
> +
> +		if (prop)
> +			fs_baudrate = *prop;
> +		of_node_put(node);
> +	};
> +
> +	return fs_baudrate;
> +}
> +
> +EXPORT_SYMBOL(get_baudrate);
> +
> +static u32 intfreq = -1;
> +
> +u32 get_intfreq(void)
> +{
> +	struct device_node *node;
> +
> +	if (intfreq != -1)
> +		return intfreq;
> +
> +	node = of_find_node_by_type(NULL, "cpu");
> +	if (node) {
> +		unsigned int size;
> +		unsigned int *prop = (unsigned int*)get_property(node, "clock- 
> frequency", &size);
> +		if (prop)
> +			intfreq = *prop;
> +		of_node_put(node);
> +	}
> +
> +	return intfreq;
> +}
> +
> +EXPORT_SYMBOL(get_intfreq);
> +

Don't we have something that reports "clock-frequency" elsewhere?

> +
>  static int __init gfar_mdio_of_init(void)
>  {
>  	struct device_node *np;
> @@ -491,3 +571,211 @@ err:
>  }
>
>  arch_initcall(fsl_usb_dr_of_init);
> +
> +static const char *fcc_regs = "fcc_regs";
> +static const char *fcc_regs_c = "fcc_regs_c";
> +static const char *fcc_pram = "fcc_pram";
> +static char bus_id[9][BUS_ID_SIZE];
> +
> +static int __init fs_enet_of_init(void)
> +{
> +	struct device_node *np;
> +	unsigned int i;
> +	struct platform_device *fs_enet_dev;
> +	struct resource res;
> +	int ret;
> +
> +	for (np = NULL, i = 0;
> +	     (np = of_find_compatible_node(np, "network", "fs_enet")) !=  
> NULL;
> +	     i++) {
> +		struct resource r[4];
> +		struct device_node *phy, *mdio;
> +		struct fs_platform_info fs_enet_data;
> +		unsigned int *id, *phy_addr;
> +		void *mac_addr;
> +		phandle *ph;
> +		char *model;
> +
> +		memset(r, 0, sizeof(r));
> +		memset(&fs_enet_data, 0, sizeof(fs_enet_data));
> +
> +		ret = of_address_to_resource(np, 0, &r[0]);
> +		if (ret)
> +			goto err;
> +		r[0].name = fcc_regs;
> +
> +		ret = of_address_to_resource(np, 1, &r[1]);
> +		if (ret)
> +			goto err;
> +		r[1].name = fcc_pram;
> +
> +		ret = of_address_to_resource(np, 2, &r[2]);
> +		if (ret)
> +			goto err;
> +		r[2].name = fcc_regs_c;
> +
> +		r[3].start = np->intrs[0].line;
> +		r[3].end = np->intrs[0].line;
> +		r[3].flags = IORESOURCE_IRQ;
> +
> +		fs_enet_dev =
> +		    platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
> +
> +		if (IS_ERR(fs_enet_dev)) {
> +			ret = PTR_ERR(fs_enet_dev);
> +			goto err;
> +		}
> +
> +		model = get_property(np, "model", NULL);
> +		if (model == NULL) {
> +			ret = -ENODEV;
> +			goto unreg;
> +		}
> +
> +		mac_addr = get_property(np, "mac-address", NULL);
> +		memcpy(fs_enet_data.macaddr, mac_addr, 6);
> +
> +		ph = (phandle *) get_property(np, "phy-handle", NULL);
> +		phy = of_find_node_by_phandle(*ph);
> +
> +		if (phy == NULL) {
> +			ret = -ENODEV;
> +			goto unreg;
> +		}
> +
> +		phy_addr = (u32 *) get_property(phy, "reg", NULL);
> +		fs_enet_data.phy_addr = *phy_addr;
> +
> +		id = (u32 *) get_property(np, "device-id", NULL);
> +		fs_enet_data.fs_no = *id;
> +
> +		mdio = of_get_parent(phy);
> +                ret = of_address_to_resource(mdio, 0, &res);
> +                if (ret) {
> +                        of_node_put(phy);
> +                        of_node_put(mdio);
> +                        goto unreg;
> +                }
> +
> +		switch (*id) {
> +		case fsid_fcc1:
> +			fs_enet_data.mem_offset = FCC1_MEM_OFFSET,
> +			snprintf((char*)&bus_id[2], BUS_ID_SIZE, "%x:%02x", (u32) 
> res.start, fs_enet_data.phy_addr);
> +			fs_enet_data.bus_id = (char*)&bus_id[2];
> +			fs_enet_data.cp_page = CPM_CR_FCC1_PAGE;
> +			fs_enet_data.cp_block = CPM_CR_FCC1_SBLOCK;
> +			break;
> +		case fsid_fcc2:
> +			fs_enet_data.mem_offset = FCC2_MEM_OFFSET,
> +			snprintf((char*)&bus_id[3], BUS_ID_SIZE, "%x:%02x", (u32) 
> res.start, fs_enet_data.phy_addr);
> +			fs_enet_data.bus_id = (char*)&bus_id[3];
> +			fs_enet_data.cp_page = CPM_CR_FCC2_PAGE;
> +			fs_enet_data.cp_block = CPM_CR_FCC2_SBLOCK;
> +			break;
> +		case fsid_fcc3:
> +			fs_enet_data.mem_offset = FCC3_MEM_OFFSET,
> +			snprintf((char*)&bus_id[4], BUS_ID_SIZE, "%x:%02x", (u32) 
> res.start, fs_enet_data.phy_addr);
> +			fs_enet_data.bus_id = (char*)&bus_id[4];
> +			fs_enet_data.cp_page = CPM_CR_FCC3_PAGE;
> +			fs_enet_data.cp_block = CPM_CR_FCC3_SBLOCK;
> +			break;
> +		}

this looks like a lot of effort to just encode a single integer (1,  
2, 3) and then lookup the other information based on it.

> +
> +		if (strstr(model, "FCC")) {
> +			fs_enet_data.dpram_offset = (u32)cpm2_immr->im_dprambase;
> +			fs_enet_data.rx_ring = 32;
> +			fs_enet_data.tx_ring = 32;
> +			fs_enet_data.rx_copybreak = 240;
> +			fs_enet_data.use_napi = 0;
> +			fs_enet_data.napi_weight = 17;
> +		}
> +
> +		of_node_put(phy);
> +		of_node_put(mdio);
> +
> +		ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
> +					     sizeof(struct
> +						    fs_platform_info));
> +		if (ret)
> +			goto unreg;
> +	}
> +	return 0;
> +
> +unreg:
> +	platform_device_unregister(fs_enet_dev);
> +err:
> +	return ret;
> +}
> +
> +arch_initcall(fs_enet_of_init);
> +
> +static const char *scc_regs = "regs";
> +static const char *scc_pram = "pram";
> +
> +static int __init cpm_uart_of_init(void)
> +{
> +	struct device_node *np;
> +	unsigned int i;
> +	struct platform_device *cpm_uart_dev;
> +	int ret;
> +
> +
> +	for (np = NULL, i = 0;
> +	     (np = of_find_compatible_node(np, "serial", "cpm_uart")) !=  
> NULL;
> +	     i++) {
> +		struct resource r[3];
> +		struct fs_uart_platform_info cpm_uart_data;
> +		int *id;
> +
> +		memset(r, 0, sizeof(r));
> +		memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
> +
> +		ret = of_address_to_resource(np, 0, &r[0]);
> +		if (ret)
> +			goto err;
> +
> +		r[0].name = scc_regs;
> +
> +		ret = of_address_to_resource(np, 1, &r[1]);
> +		if (ret)
> +			goto err;
> +		r[1].name = scc_pram;
> +
> +		r[2].start = np->intrs[0].line;
> +		r[2].end = np->intrs[0].line;
> +		r[2].flags = IORESOURCE_IRQ;
> +
> +		cpm_uart_dev =
> +		    platform_device_register_simple("fsl-cpm-scc:uart", i, &r 
> [0], 3);
> +
> +		if (IS_ERR(cpm_uart_dev)) {
> +			ret = PTR_ERR(cpm_uart_dev);
> +			goto err;
> +		}
> +
> +		id = get_property(np, "device-id", NULL);
> +		cpm_uart_data.fs_no = *id;
> +		cpm_uart_data.uart_clk = get_intfreq();
> +
> +		cpm_uart_data.tx_num_fifo = 4;
> +		cpm_uart_data.tx_buf_size = 32;
> +		cpm_uart_data.rx_num_fifo = 4;
> +		cpm_uart_data.rx_buf_size = 32;
> +
> +		ret =
> +		    platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
> +					     sizeof(struct
> +						    fs_uart_platform_info));
> +		if (ret)
> +			goto unreg;
> +	}
> +
> +	return 0;
> +
> +unreg:
> +	platform_device_unregister(cpm_uart_dev);
> +err:
> +	return ret;
> +}
> +
> +arch_initcall(cpm_uart_of_init);
> diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
> index f6a7ff0..8e6840b 100644
> --- a/include/asm-ppc/cpm2.h
> +++ b/include/asm-ppc/cpm2.h
> @@ -1186,7 +1186,7 @@ #define PC3_DIRC1	(PC3_TXDAT)
>  #define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
>  #define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
>  #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
> -#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
> +#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
>
>  #endif /* __CPM2__ */
>  #endif /* __KERNEL__ */
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/6] CPM_UART: unify clock sources
  2006-06-24 16:22       ` Jon Loeliger
@ 2006-06-24 16:27         ` Kumar Gala
  0 siblings, 0 replies; 14+ messages in thread
From: Kumar Gala @ 2006-06-24 16:27 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev


On Jun 24, 2006, at 11:22 AM, Jon Loeliger wrote:

> So, like, the other day Vitaly Bordug mumbled:
>> That was my first guess as well, but:
>> The aim is yet moving to powerpc not to break existing ppc/ stuff.
>> So if alternatively platform_data may be utilized, all relevant ppc
>> stuff that uses cpm uart should be updated. While doing the driver
>> "platformize" trick, I made it possible to keep legacy behaviour
>> (pd-less), this is not going to afford such a thing.
>>
>> IOW, I don't see much sense in updating ppc/ BSP files, just to keep
>> the right way. It does not look very neat now, but does the job of
>> moving FW and keeping existing stuff sane. If there is better  
>> approach
>> envisioned, I'll definitely follow..
>
> And don't forget that the subsequent, follow-up patches
> will be to _remove_ the 85xx family from arch/ppc as well.
> The trick right now is simply to get it working in arch/powerpc
> so that we can move forward there.  Worrying about absolute
> cleanliness in arch/ppc for 85xx shouldn't, in my opinion,
> be the highest concern.

Its a concern until we have a way of booting existing 85xx systems w/ 
their boot loaders using arch/powerpc kernels.

Also, CPM effects more than just 85xx so care needs to be taken for  
8xx & 82xx.

- k

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support
  2006-06-24 16:26   ` Kumar Gala
@ 2006-06-24 17:17     ` Vitaly Bordug
  2006-06-26 13:35       ` Kumar Gala
  0 siblings, 1 reply; 14+ messages in thread
From: Vitaly Bordug @ 2006-06-24 17:17 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev

На Sat, 24 Jun 2006 11:26:01 -0500
Kumar Gala <galak@kernel.crashing.org> записано:

> 
> On Jun 23, 2006, at 6:17 PM, Vitaly Bordug wrote:
> 
> >
> > This enables the mpc8560-specific bits in powerpc. The relevant  
> > cpm2 PIC
> > and common utility were moved without or with minor changes,
> > hereby not all
> > the stuff have OF power utilized. Current functionality depends on  
> > the very
> > latest fs_enet update, that will go through netdev (cc'd here as
> > reference). Assuming all the preceeding stuff applied (PAL+fs_enet  
> > related
> > + CPM_UART update), the both TSEC eth ,FCC Eths, and both SCC
> > UARTs are
> > working. The relevant drivers are still capable to drive users in
> > ppc, which was verified with 8272ADS (SCC uart+FCC eth).
> >
> > Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
> 
> Can you break this patch up into its pieces (moving of cpm2* files),  
> fsl_soc mods, 8560 additions.

OK.
> 
> > ---
> >
> >  arch/powerpc/lib/Makefile                 |    5 +
> >  arch/powerpc/platforms/85xx/Kconfig       |   11 +
> >  arch/powerpc/platforms/85xx/Makefile      |    1
> >  arch/powerpc/platforms/85xx/mpc8560_ads.h |   54 +++++
> >  arch/powerpc/platforms/85xx/mpc85xx_ads.c |  107 +++++++++++
> >  arch/powerpc/sysdev/Makefile              |    7 +
> >  arch/powerpc/sysdev/cpm2_common.c         |  197
> > ++++++++++++++++++++ arch/powerpc/sysdev/cpm2_pic.c            |
> > 181 ++++++++++++++++++ arch/powerpc/sysdev/cpm2_pic.h
> > |    8 + arch/powerpc/sysdev/fsl_soc.c             |  290
> > ++++++++++++++++++ +++++++++++
> >  include/asm-ppc/cpm2.h                    |    2
> >  11 files changed, 860 insertions(+), 3 deletions(-)
> >
> > diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
> > index ff70964..0993b3b 100644
> > --- a/arch/powerpc/lib/Makefile
> > +++ b/arch/powerpc/lib/Makefile
> > @@ -21,3 +21,8 @@ ifeq ($(CONFIG_PPC64),y)
> >  obj-$(CONFIG_SMP)	+= locks.o
> >  obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
> >  endif
> > +
> > +# Temporary hack until we have migrated to asm-powerpc
> > +ifeq ($(ARCH),powerpc)
> > +obj-$(CONFIG_CPM2)	+= rheap.o
> > +endif
> 
> Why not just move the file and build in arch/powerpc/lib/ for both  
> arch/powerpc & arch/ppc.  Same goes for cpm_* files.
> 

Makes sense to me...
> > diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/ 
> > platforms/85xx/Kconfig
> > index 454fc53..3d440de 100644
> > --- a/arch/powerpc/platforms/85xx/Kconfig
> > +++ b/arch/powerpc/platforms/85xx/Kconfig
> > @@ -11,6 +11,12 @@ config MPC8540_ADS
> >  	help
> >  	  This option enables support for the MPC 8540 ADS board
> >
> > +config MPC8560_ADS
> > +	bool "Freescale MPC8560 ADS"
> > +	select DEFAULT_UIMAGE
> > +	help
> > +	  This option enables support for the MPC 8560 ADS board
> > +
> >  config MPC85xx_CDS
> >  	bool "Freescale MPC85xx CDS"
> >  	select DEFAULT_UIMAGE
> > @@ -25,6 +31,11 @@ config MPC8540
> >  	select PPC_UDBG_16550
> >  	select PPC_INDIRECT_PCI
> >  	default y if MPC8540_ADS || MPC85xx_CDS
> > +
> > +config MPC8560
> > +	bool
> > +	select PPC_INDIRECT_PCI
> > +	default y if MPC8560_ADS
> >
> >  config PPC_INDIRECT_PCI_BE
> >  	bool
> > diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/ 
> > platforms/85xx/Makefile
> > index 7615aa5..282f5d0 100644
> > --- a/arch/powerpc/platforms/85xx/Makefile
> > +++ b/arch/powerpc/platforms/85xx/Makefile
> > @@ -3,4 +3,5 @@ # Makefile for the PowerPC 85xx linux ke
> >  #
> >  obj-$(CONFIG_PPC_85xx)	+= misc.o pci.o
> >  obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
> > +obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
> >  obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
> > diff --git a/arch/powerpc/platforms/85xx/mpc8560_ads.h b/arch/ 
> > powerpc/platforms/85xx/mpc8560_ads.h
> > new file mode 100644
> > index 0000000..4ebe710
> > --- /dev/null
> > +++ b/arch/powerpc/platforms/85xx/mpc8560_ads.h
> > @@ -0,0 +1,54 @@
> > +/*
> > + * MPC8560ADS board definitions
> > + *
> > + * Maintainer: Kumar Gala <galak@kernel.crashing.org>
> > + *
> > + * Copyright 2004 Freescale Semiconductor Inc.
> > + *
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef __MACH_MPC8560ADS_H
> > +#define __MACH_MPC8560ADS_H
> > +
> > +#include <linux/config.h>
> > +#include <linux/initrd.h>
> > +
> > +#define BOARD_CCSRBAR		((uint)0xe0000000)
> > +#define BCSR_ADDR		((uint)0xf8000000)
> > +#define BCSR_SIZE		((uint)(32 * 1024))
> > +
> > +#define MPC85xx_CPM_OFFSET	(0x80000)
> > +
> > +/*XXX TODO: pull from OF*/
> > +#define CPM_MAP_ADDR		(BOARD_CCSRBAR +
> > MPC85xx_CPM_OFFSET) +
> > +/* PCI interrupt controller */
> > +#define PIRQA		MPC85xx_IRQ_EXT1
> > +#define PIRQB		MPC85xx_IRQ_EXT2
> > +#define PIRQC		MPC85xx_IRQ_EXT3
> > +#define PIRQD		MPC85xx_IRQ_EXT4
> > +
> > +/* FCC1 Clock Source Configuration.  These can be
> > + * redefined in the board specific file.
> > + *    Can only choose from CLK9-12 */
> > +#define F1_RXCLK       12
> > +#define F1_TXCLK       11
> > +
> > +/* FCC2 Clock Source Configuration.  These can be
> > + * redefined in the board specific file.
> > + *    Can only choose from CLK13-16 */
> > +#define F2_RXCLK       13
> > +#define F2_TXCLK       14
> > +
> > +/* FCC3 Clock Source Configuration.  These can be
> > + * redefined in the board specific file.
> > + *    Can only choose from CLK13-16 */
> > +#define F3_RXCLK       15
> > +#define F3_TXCLK       16
> > +
> > +#endif				/* __MACH_MPC8560ADS_H */
> > diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/ 
> > powerpc/platforms/85xx/mpc85xx_ads.c
> > index 5eeff37..352d0ae 100644
> > --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> > +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> > @@ -15,6 +15,7 @@ #include <linux/config.h>
> >  #include <linux/stddef.h>
> >  #include <linux/kernel.h>
> >  #include <linux/pci.h>
> > +#include <linux/interrupt.h>
> >  #include <linux/kdev_t.h>
> >  #include <linux/delay.h>
> >  #include <linux/seq_file.h>
> > @@ -30,6 +31,10 @@ #include <asm/mpic.h>
> >  #include <mm/mmu_decl.h>
> >  #include <asm/udbg.h>
> >
> > +#ifdef CONFIG_CPM2
> > +#include <asm/cpm2.h>
> > +#endif
> > +
> >  #include <sysdev/fsl_soc.h>
> >  #include "mpc85xx.h"
> >
> > @@ -121,8 +126,25 @@ mpc85xx_exclude_device(u_char bus, u_cha
> >  }
> >
> >  #endif /* CONFIG_PCI */
> > +
> > +#ifdef CONFIG_CPM2
> >
> > +static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct  
> > pt_regs *regs)
> > +{
> > +	while ((irq = cpm2_get_irq(regs)) >= 0)
> > +		__do_IRQ(irq, regs);
> > +	return IRQ_HANDLED;
> > +}
> >
> > +static struct irqaction cpm2_irqaction = {
> > +	.handler = cpm2_cascade,
> > +	.flags = SA_INTERRUPT,
> > +	.mask = CPU_MASK_NONE,
> > +	.name = "cpm2_cascade",
> > +};
> > +
> 
> I'd prefer that we see Ben's new IRQ support before doing this, but  
> ok for now.
> 
> > +#endif /* CONFIG_CPM2 */
> > +
> >  void __init mpc85xx_ads_pic_init(void)
> >  {
> >  	struct mpic *mpic1;
> > @@ -158,15 +180,91 @@ void __init mpc85xx_ads_pic_init(void)
> >  	mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
> >  	mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
> >  	mpic_init(mpic1);
> > +
> > +#ifdef CONFIG_CPM2
> > +	/* Setup CPM2 PIC */
> > +
> > +        cpm2_init_IRQ();
> > +
> > +	setup_irq(MPC85xx_IRQ_CPM, &cpm2_irqaction);
> > +#endif
> >  }
> >
> >  /*
> >   * Setup the architecture
> > - */
> > + */
> > +static void init_fcc_ioports(void)
> > +{
> > +	struct immap *immap;
> > +	struct io_port *io;
> > +	u32 tempval;
> > +
> > +	immap = cpm2_immr;
> > +
> > +	io = &immap->im_ioport;
> > +	/* FCC2/3 are on the ports B/C. */
> > +	tempval = in_be32(&io->iop_pdirb);
> > +	tempval &= ~PB2_DIRB0;
> > +	tempval |= PB2_DIRB1;
> > +	out_be32(&io->iop_pdirb, tempval);
> > +
> > +	tempval = in_be32(&io->iop_psorb);
> > +	tempval &= ~PB2_PSORB0;
> > +	tempval |= PB2_PSORB1;
> > +	out_be32(&io->iop_psorb, tempval);
> > +
> > +	tempval = in_be32(&io->iop_pparb);
> > +	tempval |= (PB2_DIRB0 | PB2_DIRB1);
> > +	out_be32(&io->iop_pparb, tempval);
> > +
> > +	tempval = in_be32(&io->iop_pdirb);
> > +	tempval &= ~PB3_DIRB0;
> > +	tempval |= PB3_DIRB1;
> > +	out_be32(&io->iop_pdirb, tempval);
> > +
> > +	tempval = in_be32(&io->iop_psorb);
> > +	tempval &= ~PB3_PSORB0;
> > +	tempval |= PB3_PSORB1;
> > +	out_be32(&io->iop_psorb, tempval);
> > +
> > +	tempval = in_be32(&io->iop_pparb);
> > +	tempval |= (PB3_DIRB0 | PB3_DIRB1);
> > +	out_be32(&io->iop_pparb, tempval);
> > +
> > +	tempval = in_be32(&io->iop_pdirc);
> > +	tempval |= PC3_DIRC1;
> > +	out_be32(&io->iop_pdirc, tempval);
> > +
> > +	tempval = in_be32(&io->iop_pparc);
> > +	tempval |= PC3_DIRC1;
> > +	out_be32(&io->iop_pparc, tempval);
> > +
> > +	/* Port C has clocks......  */
> > +	tempval = in_be32(&io->iop_psorc);
> > +	tempval &= ~(CLK_TRX);
> > +	out_be32(&io->iop_psorc, tempval);
> > +
> > +	tempval = in_be32(&io->iop_pdirc);
> > +	tempval &= ~(CLK_TRX);
> > +	out_be32(&io->iop_pdirc, tempval);
> > +	tempval = in_be32(&io->iop_pparc);
> > +	tempval |= (CLK_TRX);
> > +	out_be32(&io->iop_pparc, tempval);
> > +
> > +	/* Configure Serial Interface clock routing.
> > +	 * First,  clear all FCC bits to zero,
> > +	 * then set the ones we want.
> > +	 */
> > +	immap->im_cpmux.cmx_fcr &= ~(CPMUX_CLK_MASK);
> > +	immap->im_cpmux.cmx_fcr |= CPMUX_CLK_ROUTE;
> > +}
> 
> Can this be turned into some library function that uses some input  
> that is board specific.  U-boot has a table that looked like a  
> reasonable approach.
> 

It's in TBD list, but not of high urgency fairly. The approach will be
what Dan suggested long ago - pmac-like feature_call that will behave
like sort of BSP ioctl(). Guess it will be good as a next step after
actual merge...

> > +
> >  static void __init mpc85xx_ads_setup_arch(void)
> >  {
> >  	struct device_node *cpu;
> >  	struct device_node *np;
> > +
> > +	cpm2_reset();
> >
> >  	if (ppc_md.progress)
> >  		ppc_md.progress("mpc85xx_ads_setup_arch()", 0);
> > @@ -184,8 +282,13 @@ static void __init mpc85xx_ads_setup_arc
> >  	}
> >
> >  #ifdef CONFIG_PCI
> > +
> >  	for (np = NULL; (np = of_find_node_by_type(np, "pci")) !=
> > NULL;) add_bridge(np);
> > +
> > +#ifdef CONFIG_CPM2
> > +	init_fcc_ioports();
> > +#endif
> 
> This appears to be inside the CONFIG_PCI #ifdef, is that really what  
> you want?
> 

touché :) Will fix...

> >  	ppc_md.pci_swizzle = common_swizzle;
> >  	ppc_md.pci_map_irq = mpc85xx_map_irq;
> > @@ -240,5 +343,7 @@ define_machine(mpc85xx_ads) {
> >  	.get_irq		= mpic_get_irq,
> >  	.restart		= mpc85xx_restart,
> >  	.calibrate_decr		= generic_calibrate_decr,
> > +#ifndef CONFIG_CPM2
> >  	.progress		= udbg_progress,
> > +#endif
> >  };
> > diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/ 
> > Makefile
> > index cef95b0..75dfe12 100644
> > --- a/arch/powerpc/sysdev/Makefile
> > +++ b/arch/powerpc/sysdev/Makefile
> > @@ -12,3 +12,10 @@ obj-$(CONFIG_U3_DART)		+=
> > dart_iommu.o obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
> >  obj-$(CONFIG_PPC_83xx)		+= ipic.o
> >  obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
> > +
> > +# Temporary hack until we have migrated to asm-powerpc
> > +ifeq ($(ARCH),powerpc)
> > +obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
> > +endif
> 
> See earlier comments about just building in arch/powerpc
> 
Hrm, here I am not completely sure it's a good thing. The point is that
currently some OF-specific stuff is under construction to go into
cpm2_common at least (for instance, getting rid of CPM_MAP_ADDR
ioremap because the offset is available via oftree, and things like
that).

> > +
> > +#obj-$(CONFIG_CPM2)		+= cpm2/
> > Yuri diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/ 
> > sysdev/cpm2_common.c
> > new file mode 100644
> > index 0000000..c755f65
> > --- /dev/null
> > +++ b/arch/powerpc/sysdev/cpm2_common.c
> > @@ -0,0 +1,197 @@
> > +/*
> > + * General Purpose functions for the global management of the
> > + * 8260 Communication Processor Module.
> > + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
> > + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
> > + *	2.3.99 Updates
> > + *
> > + * In addition to the individual control of the communication
> > + * channels, there are a few functions that globally affect the
> > + * communication processor.
> > + *
> > + * Buffer descriptors must be allocated from the dual ported memory
> > + * space.  The allocator for that is here.  When the communication
> > + * process is reset, we reclaim the memory available.  There is
> > + * currently no deallocator for this memory.
> > + */
> > +#include <linux/errno.h>
> > +#include <linux/sched.h>
> > +#include <linux/kernel.h>
> > +#include <linux/param.h>
> > +#include <linux/string.h>
> > +#include <linux/mm.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/module.h>
> > +#include <asm/io.h>
> > +#include <asm/irq.h>
> > +#include <asm/mpc8260.h>
> > +#include <asm/page.h>
> > +#include <asm/pgtable.h>
> > +#include <asm/cpm2.h>
> > +#include <asm/rheap.h>
> > +
> > +static void cpm2_dpinit(void);
> > +cpm_cpm2_t	*cpmp;		/* Pointer to comm
> > processor space */ +
> > +/* We allocate this here because it is used almost exclusively for
> > + * the communication processor devices.
> > + */
> > +cpm2_map_t *cpm2_immr;
> > +
> > +#define CPM_MAP_SIZE	(0x40000)	/* 256k - the PQ3
> > reserve this amount
> > +					   of space for CPM as it
> > is larger
> > +					   than on PQ2 */
> > +
> > +void
> > +cpm2_reset(void)
> > +{
> > +	cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR,
> > CPM_MAP_SIZE);
> 
> You dont need the cast.
> 

Ok, but this is going to be changed as I said upper. We have enough info
in dts to make this more sane. Actually, I do not like the idea of
ioremapping the whole IMMR, but that improvements are for the future.
  
> > +
> > +	/* Reclaim the DP memory for our use.
> > +	 */
> > +	cpm2_dpinit();
> > +
> > +	/* Tell everyone where the comm processor resides.
> > +	 */
> > +	cpmp = &cpm2_immr->im_cpm;
> > +}
> > +
> > +/* Set a baud rate generator.  This needs lots of work.  There are
> > + * eight BRGs, which can be connected to the CPM channels or output
> > + * as clocks.  The BRGs are in two different block of internal
> > + * memory mapped space.
> > + * The baud rate clock is the system clock divided by something.
> > + * It was set up long ago during the initial boot phase and is
> > + * is given to us.
> > + * Baud rate clocks are zero-based in the driver code (as that maps
> > + * to port numbers).  Documentation uses 1-based numbering.
> > + */
> > +#define BRG_INT_CLK	(get_brgfreq())
> > +#define BRG_UART_CLK	(BRG_INT_CLK/16)
> > +
> > +/* This function is used by UARTS, or anything else that uses a 16x
> > + * oversampled clock.
> > + */
> > +void
> > +cpm_setbrg(uint brg, uint rate)
> > +{
> > +	volatile uint	*bp;
> > +
> > +	/* This is good enough to get SMCs running.....
> > +	*/
> > +	if (brg < 4) {
> > +		bp = (uint *)&cpm2_immr->im_brgc1;
> > +	}
> > +	else {
> > +		bp = (uint *)&cpm2_immr->im_brgc5;
> > +		brg -= 4;
> > +	}
> > +	bp += brg;
> > +	*bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
> > +}
> > +
> > +/* This function is used to set high speed synchronous baud rate
> > + * clocks.
> > + */
> > +void
> > +cpm2_fastbrg(uint brg, uint rate, int div16)
> > +{
> > +	volatile uint	*bp;
> > +
> > +	if (brg < 4) {
> > +		bp = (uint *)&cpm2_immr->im_brgc1;
> > +	}
> > +	else {
> > +		bp = (uint *)&cpm2_immr->im_brgc5;
> > +		brg -= 4;
> > +	}
> > +	bp += brg;
> > +	*bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
> > +	if (div16)
> > +		*bp |= CPM_BRG_DIV16;
> > +}
> > +
> > +/*
> > + * dpalloc / dpfree bits.
> > + */
> > +static spinlock_t cpm_dpmem_lock;
> > +/* 16 blocks should be enough to satisfy all requests
> > + * until the memory subsystem goes up... */
> > +static rh_block_t cpm_boot_dpmem_rh_block[16];
> > +static rh_info_t cpm_dpmem_info;
> > +
> > +static void cpm2_dpinit(void)
> > +{
> > +	spin_lock_init(&cpm_dpmem_lock);
> > +
> > +	/* initialize the info header */
> > +	rh_init(&cpm_dpmem_info, 1,
> > +			sizeof(cpm_boot_dpmem_rh_block) /
> > +			sizeof(cpm_boot_dpmem_rh_block[0]),
> > +			cpm_boot_dpmem_rh_block);
> > +
> > +	/* Attach the usable dpmem area */
> > +	/* XXX: This is actually crap. CPM_DATAONLY_BASE and
> > +	 * CPM_DATAONLY_SIZE is only a subset of the available
> > dpram. It
> > +	 * varies with the processor and the microcode patches
> > activated.
> > +	 * But the following should be at least safe.
> > +	 */
> > +	rh_attach_region(&cpm_dpmem_info, (void
> > *)CPM_DATAONLY_BASE,
> > +			CPM_DATAONLY_SIZE);
> > +}
> > +
> > +/* This function returns an index into the DPRAM area.
> > + */
> > +uint cpm_dpalloc(uint size, uint align)
> > +{
> > +	void *start;
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&cpm_dpmem_lock, flags);
> > +	cpm_dpmem_info.alignment = align;
> > +	start = rh_alloc(&cpm_dpmem_info, size, "commproc");
> > +	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
> > +
> > +	return (uint)start;
> > +}
> > +EXPORT_SYMBOL(cpm_dpalloc);
> > +
> > +int cpm_dpfree(uint offset)
> > +{
> > +	int ret;
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&cpm_dpmem_lock, flags);
> > +	ret = rh_free(&cpm_dpmem_info, (void *)offset);
> > +	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL(cpm_dpfree);
> > +
> > +/* not sure if this is ever needed */
> > +uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
> > +{
> > +	void *start;
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&cpm_dpmem_lock, flags);
> > +	cpm_dpmem_info.alignment = align;
> > +	start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset,
> > size, "commproc");
> > +	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
> > +
> > +	return (uint)start;
> > +}
> > +EXPORT_SYMBOL(cpm_dpalloc_fixed);
> > +
> > +void cpm_dpdump(void)
> > +{
> > +	rh_dump(&cpm_dpmem_info);
> > +}
> > +EXPORT_SYMBOL(cpm_dpdump);
> > +
> > +void *cpm_dpram_addr(uint offset)
> > +{
> > +	return (void *)&cpm2_immr->im_dprambase[offset];
> > +}
> > +EXPORT_SYMBOL(cpm_dpram_addr);
> > diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/ 
> > cpm2_pic.c
> > new file mode 100644
> > index 0000000..e0db594
> > --- /dev/null
> > +++ b/arch/powerpc/sysdev/cpm2_pic.c
> > @@ -0,0 +1,181 @@
> > +/* The CPM2 internal interrupt controller.  It is usually
> > + * the only interrupt controller.
> > + * There are two 32-bit registers (high/low) for up to 64
> > + * possible interrupts.
> > + *
> > + * Now, the fun starts.....Interrupt Numbers DO NOT MAP
> > + * in a simple arithmetic fashion to mask or pending registers.
> > + * That is, interrupt 4 does not map to bit position 4.
> > + * We create two tables, indexed by vector number, to indicate
> > + * which register to use and which bit in the register to use.
> > + */
> > +
> > +#include <linux/stddef.h>
> > +#include <linux/init.h>
> > +#include <linux/sched.h>
> > +#include <linux/signal.h>
> > +#include <linux/irq.h>
> > +
> > +#include <asm/immap_cpm2.h>
> > +#include <asm/mpc8260.h>
> > +#include <asm/io.h>
> > +
> > +#include "cpm2_pic.h"
> > +
> > +static	u_char	irq_to_siureg[] = {
> > +	1, 1, 1, 1, 1, 1, 1, 1,
> > +	1, 1, 1, 1, 1, 1, 1, 1,
> > +	0, 0, 0, 0, 0, 0, 0, 0,
> > +	0, 0, 0, 0, 0, 0, 0, 0,
> > +	1, 1, 1, 1, 1, 1, 1, 1,
> > +	1, 1, 1, 1, 1, 1, 1, 1,
> > +	0, 0, 0, 0, 0, 0, 0, 0,
> > +	0, 0, 0, 0, 0, 0, 0, 0
> > +};
> > +
> > +/* bit numbers do not match the docs, these are precomputed so
> > the bit for
> > + * a given irq is (1 << irq_to_siubit[irq]) */
> > +static	u_char	irq_to_siubit[] = {
> > +	 0, 15, 14, 13, 12, 11, 10,  9,
> > +	 8,  7,  6,  5,  4,  3,  2,  1,
> > +	 2,  1,  0, 14, 13, 12, 11, 10,
> > +	 9,  8,  7,  6,  5,  4,  3,  0,
> > +	31, 30, 29, 28, 27, 26, 25, 24,
> > +	23, 22, 21, 20, 19, 18, 17, 16,
> > +	16, 17, 18, 19, 20, 21, 22, 23,
> > +	24, 25, 26, 27, 28, 29, 30, 31,
> > +};
> > +
> > +static void cpm2_mask_irq(unsigned int irq_nr)
> > +{
> > +	int	bit, word;
> > +	volatile uint	*simr;
> > +
> > +	irq_nr -= CPM_IRQ_OFFSET;
> > +
> > +	bit = irq_to_siubit[irq_nr];
> > +	word = irq_to_siureg[irq_nr];
> > +
> > +	simr = &(cpm2_immr->im_intctl.ic_simrh);
> > +	ppc_cached_irq_mask[word] &= ~(1 << bit);
> > +	simr[word] = ppc_cached_irq_mask[word];
> > +}
> > +
> > +static void cpm2_unmask_irq(unsigned int irq_nr)
> > +{
> > +	int	bit, word;
> > +	volatile uint	*simr;
> > +
> > +	irq_nr -= CPM_IRQ_OFFSET;
> > +
> > +	bit = irq_to_siubit[irq_nr];
> > +	word = irq_to_siureg[irq_nr];
> > +
> > +	simr = &(cpm2_immr->im_intctl.ic_simrh);
> > +	ppc_cached_irq_mask[word] |= 1 << bit;
> > +	simr[word] = ppc_cached_irq_mask[word];
> > +}
> > +
> > +static void cpm2_mask_and_ack(unsigned int irq_nr)
> > +{
> > +	int	bit, word;
> > +	volatile uint	*simr, *sipnr;
> > +
> > +	irq_nr -= CPM_IRQ_OFFSET;
> > +
> > +	bit = irq_to_siubit[irq_nr];
> > +	word = irq_to_siureg[irq_nr];
> > +
> > +	simr = &(cpm2_immr->im_intctl.ic_simrh);
> > +	sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
> > +	ppc_cached_irq_mask[word] &= ~(1 << bit);
> > +	simr[word] = ppc_cached_irq_mask[word];
> > +	sipnr[word] = 1 << bit;
> > +}
> > +
> > +static void cpm2_end_irq(unsigned int irq_nr)
> > +{
> > +	int	bit, word;
> > +	volatile uint	*simr;
> > +
> > +	if (!(irq_desc[irq_nr].status &
> > (IRQ_DISABLED|IRQ_INPROGRESS))
> > +			&& irq_desc[irq_nr].action) {
> > +
> > +		irq_nr -= CPM_IRQ_OFFSET;
> > +		bit = irq_to_siubit[irq_nr];
> > +		word = irq_to_siureg[irq_nr];
> > +
> > +		simr = &(cpm2_immr->im_intctl.ic_simrh);
> > +		ppc_cached_irq_mask[word] |= 1 << bit;
> > +		simr[word] = ppc_cached_irq_mask[word];
> > +		/*
> > +		 * Work around large numbers of spurious IRQs on
> > PowerPC 82xx
> > +		 * systems.
> > +		 */
> > +		mb();
> > +	}
> > +}
> > +
> > +static struct hw_interrupt_type cpm2_pic = {
> > +	.typename = " CPM2 SIU ",
> > +	.enable = cpm2_unmask_irq,
> > +	.disable = cpm2_mask_irq,
> > +	.ack = cpm2_mask_and_ack,
> > +	.end = cpm2_end_irq,
> > +};
> > +
> > +int cpm2_get_irq(struct pt_regs *regs)
> > +{
> > +	int irq;
> > +        unsigned long bits;
> > +
> > +        /* For CPM2, read the SIVEC register and shift the bits
> > down
> > +         * to get the irq number.         */
> > +        bits = cpm2_immr->im_intctl.ic_sivec;
> > +        irq = bits >> 26;
> > +
> > +	if (irq == 0)
> > +		return(-1);
> > +	return irq+CPM_IRQ_OFFSET;
> > +}
> > +
> > +void cpm2_init_IRQ(void)
> > +{
> > +	int i;
> > +	u32 addr;
> > +
> > +	/* Clear the CPM IRQ controller, in case it has any bits
> > set
> > +	 * from the bootloader
> > +	 */
> > +
> > +	/* Mask out everything */
> > +
> > +	cpm2_immr->im_intctl.ic_simrh = 0x00000000;
> > +	cpm2_immr->im_intctl.ic_simrl = 0x00000000;
> > +
> > +	wmb();
> > +
> > +	/* Ack everything */
> > +	cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
> > +	cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
> > +	wmb();
> > +
> > +	/* Dummy read of the vector */
> > +	i = cpm2_immr->im_intctl.ic_sivec;
> > +	rmb();
> > +
> > +	/* Initialize the default interrupt mapping priorities,
> > +	 * in case the boot rom changed something on us.
> > +	 */
> > +	cpm2_immr->im_intctl.ic_sicr = 0;
> > +	cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
> > +	cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
> > +
> > +
> > +	/* Enable chaining to OpenPIC, and make everything level
> > +	 */
> > +	for (i = 0; i < NR_CPM_INTS; i++) {
> > +		irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
> > +		irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
> > +	}
> > +}
> > diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/ 
> > cpm2_pic.h
> > new file mode 100644
> > index 0000000..97cab8f
> > --- /dev/null
> > +++ b/arch/powerpc/sysdev/cpm2_pic.h
> > @@ -0,0 +1,8 @@
> > +#ifndef _PPC_KERNEL_CPM2_H
> > +#define _PPC_KERNEL_CPM2_H
> > +
> > +extern int cpm2_get_irq(struct pt_regs *regs);
> > +
> > +extern void cpm2_init_IRQ(void);
> > +
> > +#endif /* _PPC_KERNEL_CPM2_H */
> > diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/ 
> > fsl_soc.c
> > index ceb5846..bab202d 100644
> > --- a/arch/powerpc/sysdev/fsl_soc.c
> > +++ b/arch/powerpc/sysdev/fsl_soc.c
> > @@ -21,6 +21,8 @@ #include <linux/module.h>
> >  #include <linux/device.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/fsl_devices.h>
> > +#include <linux/fs_enet_pd.h>
> > +#include <linux/fs_uart_pd.h>
> >
> >  #include <asm/system.h>
> >  #include <asm/atomic.h>
> > @@ -30,6 +32,10 @@ #include <asm/prom.h>
> >  #include <sysdev/fsl_soc.h>
> >  #include <mm/mmu_decl.h>
> >
> > +#ifdef CONFIG_CPM2
> > +#include <asm/cpm2.h>
> > +#endif
> > +
> >  static phys_addr_t immrbase = -1;
> >
> >  phys_addr_t get_immrbase(void)
> > @@ -43,7 +49,9 @@ phys_addr_t get_immrbase(void)
> >  	if (soc) {
> >  		unsigned int size;
> >  		void *prop = get_property(soc, "reg", &size);
> > -		immrbase = of_translate_address(soc, prop);
> > +
> > +		if (prop)
> > +			immrbase = of_translate_address(soc, prop);
> >  		of_node_put(soc);
> >  	};
> >
> > @@ -51,7 +59,79 @@ phys_addr_t get_immrbase(void)
> >  }
> >
> >  EXPORT_SYMBOL(get_immrbase);
> > +
> > +static u32 brgfreq = -1;
> > +
> > +u32 get_brgfreq(void)
> > +{
> > +	struct device_node *node;
> > +
> > +	if (brgfreq != -1)
> > +		return brgfreq;
> > +
> > +	node = of_find_node_by_type(NULL, "serial");
> > +	if (node) {
> > +		unsigned int size;
> > +		unsigned int *prop = (unsigned
> > int*)get_property(node, "clock- frequency", &size);
> > +
> > +		if (prop)
> > +			brgfreq = *prop;
> > +		of_node_put(node);
> > +	};
> > +
> > +	return brgfreq;
> > +}
> 
> These seems broken on a system w/both CPM & 8250 style uarts.
> 
Yeah, missed that.

> > +
> > +EXPORT_SYMBOL(get_brgfreq);
> > +
> > +static u32 fs_baudrate = -1;
> > +
> > +u32 get_baudrate(void)
> > +{
> > +	struct device_node *node;
> >
> > +	if (fs_baudrate != -1)
> > +		return fs_baudrate;
> > +
> > +	node = of_find_node_by_type(NULL, "serial");
> > +	if (node) {
> > +		unsigned int size;
> > +		unsigned int *prop = (unsigned
> > int*)get_property(node, "current- speed", &size);
> > +
> > +		if (prop)
> > +			fs_baudrate = *prop;
> > +		of_node_put(node);
> > +	};
> > +
> > +	return fs_baudrate;
> > +}
> > +
> > +EXPORT_SYMBOL(get_baudrate);
> > +
> > +static u32 intfreq = -1;
> > +
> > +u32 get_intfreq(void)
> > +{
> > +	struct device_node *node;
> > +
> > +	if (intfreq != -1)
> > +		return intfreq;
> > +
> > +	node = of_find_node_by_type(NULL, "cpu");
> > +	if (node) {
> > +		unsigned int size;
> > +		unsigned int *prop = (unsigned
> > int*)get_property(node, "clock- frequency", &size);
> > +		if (prop)
> > +			intfreq = *prop;
> > +		of_node_put(node);
> > +	}
> > +
> > +	return intfreq;
> > +}
> > +
> > +EXPORT_SYMBOL(get_intfreq);
> > +
> 
> Don't we have something that reports "clock-frequency" elsewhere?
> 

If yes, I haven't found... Mind pointing where to look at? 

> > +
> >  static int __init gfar_mdio_of_init(void)
> >  {
> >  	struct device_node *np;
> > @@ -491,3 +571,211 @@ err:
> >  }
> >
> >  arch_initcall(fsl_usb_dr_of_init);
> > +
> > +static const char *fcc_regs = "fcc_regs";
> > +static const char *fcc_regs_c = "fcc_regs_c";
> > +static const char *fcc_pram = "fcc_pram";
> > +static char bus_id[9][BUS_ID_SIZE];
> > +
> > +static int __init fs_enet_of_init(void)
> > +{
> > +	struct device_node *np;
> > +	unsigned int i;
> > +	struct platform_device *fs_enet_dev;
> > +	struct resource res;
> > +	int ret;
> > +
> > +	for (np = NULL, i = 0;
> > +	     (np = of_find_compatible_node(np, "network",
> > "fs_enet")) != NULL;
> > +	     i++) {
> > +		struct resource r[4];
> > +		struct device_node *phy, *mdio;
> > +		struct fs_platform_info fs_enet_data;
> > +		unsigned int *id, *phy_addr;
> > +		void *mac_addr;
> > +		phandle *ph;
> > +		char *model;
> > +
> > +		memset(r, 0, sizeof(r));
> > +		memset(&fs_enet_data, 0, sizeof(fs_enet_data));
> > +
> > +		ret = of_address_to_resource(np, 0, &r[0]);
> > +		if (ret)
> > +			goto err;
> > +		r[0].name = fcc_regs;
> > +
> > +		ret = of_address_to_resource(np, 1, &r[1]);
> > +		if (ret)
> > +			goto err;
> > +		r[1].name = fcc_pram;
> > +
> > +		ret = of_address_to_resource(np, 2, &r[2]);
> > +		if (ret)
> > +			goto err;
> > +		r[2].name = fcc_regs_c;
> > +
> > +		r[3].start = np->intrs[0].line;
> > +		r[3].end = np->intrs[0].line;
> > +		r[3].flags = IORESOURCE_IRQ;
> > +
> > +		fs_enet_dev =
> > +		    platform_device_register_simple("fsl-cpm-fcc",
> > i, &r[0], 4); +
> > +		if (IS_ERR(fs_enet_dev)) {
> > +			ret = PTR_ERR(fs_enet_dev);
> > +			goto err;
> > +		}
> > +
> > +		model = get_property(np, "model", NULL);
> > +		if (model == NULL) {
> > +			ret = -ENODEV;
> > +			goto unreg;
> > +		}
> > +
> > +		mac_addr = get_property(np, "mac-address", NULL);
> > +		memcpy(fs_enet_data.macaddr, mac_addr, 6);
> > +
> > +		ph = (phandle *) get_property(np, "phy-handle",
> > NULL);
> > +		phy = of_find_node_by_phandle(*ph);
> > +
> > +		if (phy == NULL) {
> > +			ret = -ENODEV;
> > +			goto unreg;
> > +		}
> > +
> > +		phy_addr = (u32 *) get_property(phy, "reg", NULL);
> > +		fs_enet_data.phy_addr = *phy_addr;
> > +
> > +		id = (u32 *) get_property(np, "device-id", NULL);
> > +		fs_enet_data.fs_no = *id;
> > +
> > +		mdio = of_get_parent(phy);
> > +                ret = of_address_to_resource(mdio, 0, &res);
> > +                if (ret) {
> > +                        of_node_put(phy);
> > +                        of_node_put(mdio);
> > +                        goto unreg;
> > +                }
> > +
> > +		switch (*id) {
> > +		case fsid_fcc1:
> > +			fs_enet_data.mem_offset = FCC1_MEM_OFFSET,
> > +			snprintf((char*)&bus_id[2], BUS_ID_SIZE,
> > "%x:%02x", (u32) res.start, fs_enet_data.phy_addr);
> > +			fs_enet_data.bus_id = (char*)&bus_id[2];
> > +			fs_enet_data.cp_page = CPM_CR_FCC1_PAGE;
> > +			fs_enet_data.cp_block = CPM_CR_FCC1_SBLOCK;
> > +			break;
> > +		case fsid_fcc2:
> > +			fs_enet_data.mem_offset = FCC2_MEM_OFFSET,
> > +			snprintf((char*)&bus_id[3], BUS_ID_SIZE,
> > "%x:%02x", (u32) res.start, fs_enet_data.phy_addr);
> > +			fs_enet_data.bus_id = (char*)&bus_id[3];
> > +			fs_enet_data.cp_page = CPM_CR_FCC2_PAGE;
> > +			fs_enet_data.cp_block = CPM_CR_FCC2_SBLOCK;
> > +			break;
> > +		case fsid_fcc3:
> > +			fs_enet_data.mem_offset = FCC3_MEM_OFFSET,
> > +			snprintf((char*)&bus_id[4], BUS_ID_SIZE,
> > "%x:%02x", (u32) res.start, fs_enet_data.phy_addr);
> > +			fs_enet_data.bus_id = (char*)&bus_id[4];
> > +			fs_enet_data.cp_page = CPM_CR_FCC3_PAGE;
> > +			fs_enet_data.cp_block = CPM_CR_FCC3_SBLOCK;
> > +			break;
> > +		}
> 
> this looks like a lot of effort to just encode a single integer (1,  
> 2, 3) and then lookup the other information based on it.
> 

Not sure I am following what is suggested here. Could it be elaborated
a little bit ? 

> > +
> > +		if (strstr(model, "FCC")) {
> > +			fs_enet_data.dpram_offset =
> > (u32)cpm2_immr->im_dprambase;
> > +			fs_enet_data.rx_ring = 32;
> > +			fs_enet_data.tx_ring = 32;
> > +			fs_enet_data.rx_copybreak = 240;
> > +			fs_enet_data.use_napi = 0;
> > +			fs_enet_data.napi_weight = 17;
> > +		}
> > +
> > +		of_node_put(phy);
> > +		of_node_put(mdio);
> > +
> > +		ret = platform_device_add_data(fs_enet_dev,
> > &fs_enet_data,
> > +					     sizeof(struct
> > +
> > fs_platform_info));
> > +		if (ret)
> > +			goto unreg;
> > +	}
> > +	return 0;
> > +
> > +unreg:
> > +	platform_device_unregister(fs_enet_dev);
> > +err:
> > +	return ret;
> > +}
> > +
> > +arch_initcall(fs_enet_of_init);
> > +
> > +static const char *scc_regs = "regs";
> > +static const char *scc_pram = "pram";
> > +
> > +static int __init cpm_uart_of_init(void)
> > +{
> > +	struct device_node *np;
> > +	unsigned int i;
> > +	struct platform_device *cpm_uart_dev;
> > +	int ret;
> > +
> > +
> > +	for (np = NULL, i = 0;
> > +	     (np = of_find_compatible_node(np, "serial",
> > "cpm_uart")) != NULL;
> > +	     i++) {
> > +		struct resource r[3];
> > +		struct fs_uart_platform_info cpm_uart_data;
> > +		int *id;
> > +
> > +		memset(r, 0, sizeof(r));
> > +		memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
> > +
> > +		ret = of_address_to_resource(np, 0, &r[0]);
> > +		if (ret)
> > +			goto err;
> > +
> > +		r[0].name = scc_regs;
> > +
> > +		ret = of_address_to_resource(np, 1, &r[1]);
> > +		if (ret)
> > +			goto err;
> > +		r[1].name = scc_pram;
> > +
> > +		r[2].start = np->intrs[0].line;
> > +		r[2].end = np->intrs[0].line;
> > +		r[2].flags = IORESOURCE_IRQ;
> > +
> > +		cpm_uart_dev =
> > +
> > platform_device_register_simple("fsl-cpm-scc:uart", i, &r [0], 3);
> > +
> > +		if (IS_ERR(cpm_uart_dev)) {
> > +			ret = PTR_ERR(cpm_uart_dev);
> > +			goto err;
> > +		}
> > +
> > +		id = get_property(np, "device-id", NULL);
> > +		cpm_uart_data.fs_no = *id;
> > +		cpm_uart_data.uart_clk = get_intfreq();
> > +
> > +		cpm_uart_data.tx_num_fifo = 4;
> > +		cpm_uart_data.tx_buf_size = 32;
> > +		cpm_uart_data.rx_num_fifo = 4;
> > +		cpm_uart_data.rx_buf_size = 32;
> > +
> > +		ret =
> > +		    platform_device_add_data(cpm_uart_dev,
> > &cpm_uart_data,
> > +					     sizeof(struct
> > +
> > fs_uart_platform_info));
> > +		if (ret)
> > +			goto unreg;
> > +	}
> > +
> > +	return 0;
> > +
> > +unreg:
> > +	platform_device_unregister(cpm_uart_dev);
> > +err:
> > +	return ret;
> > +}
> > +
> > +arch_initcall(cpm_uart_of_init);
> > diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
> > index f6a7ff0..8e6840b 100644
> > --- a/include/asm-ppc/cpm2.h
> > +++ b/include/asm-ppc/cpm2.h
> > @@ -1186,7 +1186,7 @@ #define PC3_DIRC1	(PC3_TXDAT)
> >  #define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
> >  #define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
> >  #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
> > -#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
> > +#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
> >
> >  #endif /* __CPM2__ */
> >  #endif /* __KERNEL__ */
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-dev
> 
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support
  2006-06-24 17:17     ` Vitaly Bordug
@ 2006-06-26 13:35       ` Kumar Gala
  0 siblings, 0 replies; 14+ messages in thread
From: Kumar Gala @ 2006-06-26 13:35 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev

[snip]

>>> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/
>>> Makefile
>>> index cef95b0..75dfe12 100644
>>> --- a/arch/powerpc/sysdev/Makefile
>>> +++ b/arch/powerpc/sysdev/Makefile
>>> @@ -12,3 +12,10 @@ obj-$(CONFIG_U3_DART)		+=
>>> dart_iommu.o obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
>>>  obj-$(CONFIG_PPC_83xx)		+= ipic.o
>>>  obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
>>> +
>>> +# Temporary hack until we have migrated to asm-powerpc
>>> +ifeq ($(ARCH),powerpc)
>>> +obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
>>> +endif
>>
>> See earlier comments about just building in arch/powerpc
>>
> Hrm, here I am not completely sure it's a good thing. The point is  
> that
> currently some OF-specific stuff is under construction to go into
> cpm2_common at least (for instance, getting rid of CPM_MAP_ADDR
> ioremap because the offset is available via oftree, and things like
> that).

If that's the case, make a duplicate of cpm2_common.c, however I dont  
think you need the ifeq... to make that work.

>>> +
>>> +#obj-$(CONFIG_CPM2)		+= cpm2/

what's in the cpm2 directory?

[snip]

>>> diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/
>>> fsl_soc.c
>>> index ceb5846..bab202d 100644
>>> --- a/arch/powerpc/sysdev/fsl_soc.c
>>> +++ b/arch/powerpc/sysdev/fsl_soc.c
>>> @@ -21,6 +21,8 @@ #include <linux/module.h>
>>>  #include <linux/device.h>
>>>  #include <linux/platform_device.h>
>>>  #include <linux/fsl_devices.h>
>>> +#include <linux/fs_enet_pd.h>
>>> +#include <linux/fs_uart_pd.h>
>>>
>>>  #include <asm/system.h>
>>>  #include <asm/atomic.h>
>>> @@ -30,6 +32,10 @@ #include <asm/prom.h>
>>>  #include <sysdev/fsl_soc.h>
>>>  #include <mm/mmu_decl.h>
>>>
>>> +#ifdef CONFIG_CPM2
>>> +#include <asm/cpm2.h>
>>> +#endif
>>> +
>>>  static phys_addr_t immrbase = -1;
>>>
>>>  phys_addr_t get_immrbase(void)
>>> @@ -43,7 +49,9 @@ phys_addr_t get_immrbase(void)
>>>  	if (soc) {
>>>  		unsigned int size;
>>>  		void *prop = get_property(soc, "reg", &size);
>>> -		immrbase = of_translate_address(soc, prop);
>>> +
>>> +		if (prop)
>>> +			immrbase = of_translate_address(soc, prop);
>>>  		of_node_put(soc);
>>>  	};
>>>
>>> @@ -51,7 +59,79 @@ phys_addr_t get_immrbase(void)
>>>  }
>>>
>>>  EXPORT_SYMBOL(get_immrbase);
>>> +
>>> +static u32 brgfreq = -1;
>>> +
>>> +u32 get_brgfreq(void)
>>> +{
>>> +	struct device_node *node;
>>> +
>>> +	if (brgfreq != -1)
>>> +		return brgfreq;
>>> +
>>> +	node = of_find_node_by_type(NULL, "serial");
>>> +	if (node) {
>>> +		unsigned int size;
>>> +		unsigned int *prop = (unsigned
>>> int*)get_property(node, "clock- frequency", &size);
>>> +
>>> +		if (prop)
>>> +			brgfreq = *prop;
>>> +		of_node_put(node);
>>> +	};
>>> +
>>> +	return brgfreq;
>>> +}
>>
>> These seems broken on a system w/both CPM & 8250 style uarts.
>>
> Yeah, missed that.
>
>>> +
>>> +EXPORT_SYMBOL(get_brgfreq);
>>> +
>>> +static u32 fs_baudrate = -1;
>>> +
>>> +u32 get_baudrate(void)
>>> +{
>>> +	struct device_node *node;
>>>
>>> +	if (fs_baudrate != -1)
>>> +		return fs_baudrate;
>>> +
>>> +	node = of_find_node_by_type(NULL, "serial");
>>> +	if (node) {
>>> +		unsigned int size;
>>> +		unsigned int *prop = (unsigned
>>> int*)get_property(node, "current- speed", &size);
>>> +
>>> +		if (prop)
>>> +			fs_baudrate = *prop;
>>> +		of_node_put(node);
>>> +	};
>>> +
>>> +	return fs_baudrate;
>>> +}
>>> +
>>> +EXPORT_SYMBOL(get_baudrate);
>>> +
>>> +static u32 intfreq = -1;
>>> +
>>> +u32 get_intfreq(void)
>>> +{
>>> +	struct device_node *node;
>>> +
>>> +	if (intfreq != -1)
>>> +		return intfreq;
>>> +
>>> +	node = of_find_node_by_type(NULL, "cpu");
>>> +	if (node) {
>>> +		unsigned int size;
>>> +		unsigned int *prop = (unsigned
>>> int*)get_property(node, "clock- frequency", &size);
>>> +		if (prop)
>>> +			intfreq = *prop;
>>> +		of_node_put(node);
>>> +	}
>>> +
>>> +	return intfreq;
>>> +}
>>> +
>>> +EXPORT_SYMBOL(get_intfreq);
>>> +
>>
>> Don't we have something that reports "clock-frequency" elsewhere?
>>
>
> If yes, I haven't found... Mind pointing where to look at?

ppc_proc_freq in kernel/time.c

>>> +
>>>  static int __init gfar_mdio_of_init(void)
>>>  {
>>>  	struct device_node *np;
>>> @@ -491,3 +571,211 @@ err:
>>>  }
>>>
>>>  arch_initcall(fsl_usb_dr_of_init);
>>> +
>>> +static const char *fcc_regs = "fcc_regs";
>>> +static const char *fcc_regs_c = "fcc_regs_c";
>>> +static const char *fcc_pram = "fcc_pram";
>>> +static char bus_id[9][BUS_ID_SIZE];
>>> +
>>> +static int __init fs_enet_of_init(void)
>>> +{
>>> +	struct device_node *np;
>>> +	unsigned int i;
>>> +	struct platform_device *fs_enet_dev;
>>> +	struct resource res;
>>> +	int ret;
>>> +
>>> +	for (np = NULL, i = 0;
>>> +	     (np = of_find_compatible_node(np, "network",
>>> "fs_enet")) != NULL;
>>> +	     i++) {
>>> +		struct resource r[4];
>>> +		struct device_node *phy, *mdio;
>>> +		struct fs_platform_info fs_enet_data;
>>> +		unsigned int *id, *phy_addr;
>>> +		void *mac_addr;
>>> +		phandle *ph;
>>> +		char *model;
>>> +
>>> +		memset(r, 0, sizeof(r));
>>> +		memset(&fs_enet_data, 0, sizeof(fs_enet_data));
>>> +
>>> +		ret = of_address_to_resource(np, 0, &r[0]);
>>> +		if (ret)
>>> +			goto err;
>>> +		r[0].name = fcc_regs;
>>> +
>>> +		ret = of_address_to_resource(np, 1, &r[1]);
>>> +		if (ret)
>>> +			goto err;
>>> +		r[1].name = fcc_pram;
>>> +
>>> +		ret = of_address_to_resource(np, 2, &r[2]);
>>> +		if (ret)
>>> +			goto err;
>>> +		r[2].name = fcc_regs_c;
>>> +
>>> +		r[3].start = np->intrs[0].line;
>>> +		r[3].end = np->intrs[0].line;
>>> +		r[3].flags = IORESOURCE_IRQ;
>>> +
>>> +		fs_enet_dev =
>>> +		    platform_device_register_simple("fsl-cpm-fcc",
>>> i, &r[0], 4); +
>>> +		if (IS_ERR(fs_enet_dev)) {
>>> +			ret = PTR_ERR(fs_enet_dev);
>>> +			goto err;
>>> +		}
>>> +
>>> +		model = get_property(np, "model", NULL);
>>> +		if (model == NULL) {
>>> +			ret = -ENODEV;
>>> +			goto unreg;
>>> +		}
>>> +
>>> +		mac_addr = get_property(np, "mac-address", NULL);
>>> +		memcpy(fs_enet_data.macaddr, mac_addr, 6);
>>> +
>>> +		ph = (phandle *) get_property(np, "phy-handle",
>>> NULL);
>>> +		phy = of_find_node_by_phandle(*ph);
>>> +
>>> +		if (phy == NULL) {
>>> +			ret = -ENODEV;
>>> +			goto unreg;
>>> +		}
>>> +
>>> +		phy_addr = (u32 *) get_property(phy, "reg", NULL);
>>> +		fs_enet_data.phy_addr = *phy_addr;
>>> +
>>> +		id = (u32 *) get_property(np, "device-id", NULL);
>>> +		fs_enet_data.fs_no = *id;
>>> +
>>> +		mdio = of_get_parent(phy);
>>> +                ret = of_address_to_resource(mdio, 0, &res);
>>> +                if (ret) {
>>> +                        of_node_put(phy);
>>> +                        of_node_put(mdio);
>>> +                        goto unreg;
>>> +                }
>>> +
>>> +		switch (*id) {
>>> +		case fsid_fcc1:
>>> +			fs_enet_data.mem_offset = FCC1_MEM_OFFSET,
>>> +			snprintf((char*)&bus_id[2], BUS_ID_SIZE,
>>> "%x:%02x", (u32) res.start, fs_enet_data.phy_addr);
>>> +			fs_enet_data.bus_id = (char*)&bus_id[2];
>>> +			fs_enet_data.cp_page = CPM_CR_FCC1_PAGE;
>>> +			fs_enet_data.cp_block = CPM_CR_FCC1_SBLOCK;
>>> +			break;
>>> +		case fsid_fcc2:
>>> +			fs_enet_data.mem_offset = FCC2_MEM_OFFSET,
>>> +			snprintf((char*)&bus_id[3], BUS_ID_SIZE,
>>> "%x:%02x", (u32) res.start, fs_enet_data.phy_addr);
>>> +			fs_enet_data.bus_id = (char*)&bus_id[3];
>>> +			fs_enet_data.cp_page = CPM_CR_FCC2_PAGE;
>>> +			fs_enet_data.cp_block = CPM_CR_FCC2_SBLOCK;
>>> +			break;
>>> +		case fsid_fcc3:
>>> +			fs_enet_data.mem_offset = FCC3_MEM_OFFSET,
>>> +			snprintf((char*)&bus_id[4], BUS_ID_SIZE,
>>> "%x:%02x", (u32) res.start, fs_enet_data.phy_addr);
>>> +			fs_enet_data.bus_id = (char*)&bus_id[4];
>>> +			fs_enet_data.cp_page = CPM_CR_FCC3_PAGE;
>>> +			fs_enet_data.cp_block = CPM_CR_FCC3_SBLOCK;
>>> +			break;
>>> +		}
>>
>> this looks like a lot of effort to just encode a single integer (1,
>> 2, 3) and then lookup the other information based on it.
>>
>
> Not sure I am following what is suggested here. Could it be elaborated
> a little bit ?

I saying all you need to store is the fact that its a FCC and its  
number 1, 2, 3... after which we can have some table in cpm2_common.c  
that provides back cp_page, cp_block based on type and number.   
Encoding it fs_enet_data is just a duplication.

>>> +
>>> +		if (strstr(model, "FCC")) {
>>> +			fs_enet_data.dpram_offset =
>>> (u32)cpm2_immr->im_dprambase;
>>> +			fs_enet_data.rx_ring = 32;
>>> +			fs_enet_data.tx_ring = 32;
>>> +			fs_enet_data.rx_copybreak = 240;
>>> +			fs_enet_data.use_napi = 0;
>>> +			fs_enet_data.napi_weight = 17;
>>> +		}
>>> +
>>> +		of_node_put(phy);
>>> +		of_node_put(mdio);
>>> +
>>> +		ret = platform_device_add_data(fs_enet_dev,
>>> &fs_enet_data,
>>> +					     sizeof(struct
>>> +
>>> fs_platform_info));
>>> +		if (ret)
>>> +			goto unreg;
>>> +	}
>>> +	return 0;
>>> +
>>> +unreg:
>>> +	platform_device_unregister(fs_enet_dev);
>>> +err:
>>> +	return ret;
>>> +}
>>> +
>>> +arch_initcall(fs_enet_of_init);
>>> +
>>> +static const char *scc_regs = "regs";
>>> +static const char *scc_pram = "pram";
>>> +
>>> +static int __init cpm_uart_of_init(void)
>>> +{
>>> +	struct device_node *np;
>>> +	unsigned int i;
>>> +	struct platform_device *cpm_uart_dev;
>>> +	int ret;
>>> +
>>> +
>>> +	for (np = NULL, i = 0;
>>> +	     (np = of_find_compatible_node(np, "serial",
>>> "cpm_uart")) != NULL;
>>> +	     i++) {
>>> +		struct resource r[3];
>>> +		struct fs_uart_platform_info cpm_uart_data;
>>> +		int *id;
>>> +
>>> +		memset(r, 0, sizeof(r));
>>> +		memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
>>> +
>>> +		ret = of_address_to_resource(np, 0, &r[0]);
>>> +		if (ret)
>>> +			goto err;
>>> +
>>> +		r[0].name = scc_regs;
>>> +
>>> +		ret = of_address_to_resource(np, 1, &r[1]);
>>> +		if (ret)
>>> +			goto err;
>>> +		r[1].name = scc_pram;
>>> +
>>> +		r[2].start = np->intrs[0].line;
>>> +		r[2].end = np->intrs[0].line;
>>> +		r[2].flags = IORESOURCE_IRQ;
>>> +
>>> +		cpm_uart_dev =
>>> +
>>> platform_device_register_simple("fsl-cpm-scc:uart", i, &r [0], 3);
>>> +
>>> +		if (IS_ERR(cpm_uart_dev)) {
>>> +			ret = PTR_ERR(cpm_uart_dev);
>>> +			goto err;
>>> +		}
>>> +
>>> +		id = get_property(np, "device-id", NULL);
>>> +		cpm_uart_data.fs_no = *id;
>>> +		cpm_uart_data.uart_clk = get_intfreq();
>>> +
>>> +		cpm_uart_data.tx_num_fifo = 4;
>>> +		cpm_uart_data.tx_buf_size = 32;
>>> +		cpm_uart_data.rx_num_fifo = 4;
>>> +		cpm_uart_data.rx_buf_size = 32;
>>> +
>>> +		ret =
>>> +		    platform_device_add_data(cpm_uart_dev,
>>> &cpm_uart_data,
>>> +					     sizeof(struct
>>> +
>>> fs_uart_platform_info));
>>> +		if (ret)
>>> +			goto unreg;
>>> +	}
>>> +
>>> +	return 0;
>>> +
>>> +unreg:
>>> +	platform_device_unregister(cpm_uart_dev);
>>> +err:
>>> +	return ret;
>>> +}
>>> +
>>> +arch_initcall(cpm_uart_of_init);
>>> diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
>>> index f6a7ff0..8e6840b 100644
>>> --- a/include/asm-ppc/cpm2.h
>>> +++ b/include/asm-ppc/cpm2.h
>>> @@ -1186,7 +1186,7 @@ #define PC3_DIRC1	(PC3_TXDAT)
>>>  #define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
>>>  #define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
>>>  #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
>>> -#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
>>> +#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
>>>
>>>  #endif /* __CPM2__ */
>>>  #endif /* __KERNEL__ */
>>> _______________________________________________
>>> Linuxppc-dev mailing list
>>> Linuxppc-dev@ozlabs.org
>>> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>>
>>

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2006-06-26 13:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20060623231648.6721.3495.stgit@localhost.localdomain>
2006-06-23 23:16 ` [PATCH 1/6] PAL: Support of the fixed PHY Vitaly Bordug
2006-06-23 23:16 ` [PATCH 2/6] FS_ENET: Utilize Phy abstraction Vitaly Bordug
2006-06-23 23:17 ` [PATCH 3/6] FS_ENET: use PAL for mii management (BSP part) Vitaly Bordug
2006-06-23 23:17 ` [PATCH 4/6] FS_ENET: phydev pointer may be dereferenced without NULL check Vitaly Bordug
2006-06-23 23:17 ` [PATCH 5/6] CPM_UART: unify clock sources Vitaly Bordug
2006-06-24 13:46   ` Kumar Gala
2006-06-24 15:21     ` Vitaly Bordug
2006-06-24 15:50       ` Kumar Gala
2006-06-24 16:22       ` Jon Loeliger
2006-06-24 16:27         ` Kumar Gala
2006-06-23 23:17 ` [PATCH 6/6] [RFC] POWERPC: Add mpc8560 board support Vitaly Bordug
2006-06-24 16:26   ` Kumar Gala
2006-06-24 17:17     ` Vitaly Bordug
2006-06-26 13:35       ` Kumar Gala

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).