This adds board-specific files needed to utilize fs_enet Ethernet driver
for MPC885ADS and MPC866ADS.

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


---

  arch/ppc/Kconfig                     |   47 ++++
  arch/ppc/platforms/Makefile          |    2
  arch/ppc/platforms/fads.h            |    2
  arch/ppc/platforms/mpc866ads_setup.c |  290 ++++++++++++++++++++++++
  arch/ppc/platforms/mpc885ads_setup.c |  408 ++++++++++++++++++++++++++++++++++
  5 files changed, 748 insertions(+), 1 deletions(-)
  create mode 100644 arch/ppc/platforms/mpc866ads_setup.c
  create mode 100644 arch/ppc/platforms/mpc885ads_setup.c

applies-to: f358a802ba9f62bb4777d5f626f2972d1b0fa43b
4c4f454bd8e79fd67bc86aa9a22604f66d682d3b
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 8fa51b0..8e6fcb2 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -506,6 +506,53 @@ config WINCEPT

  endchoice

+menu "Freescale Ethernet driver platform-specific options"
+       depends on FS_ENET
+
+       config MPC8xx_SECOND_ETH
+       bool "Second Ethernet channel"
+       depends on (MPC885ADS || MPC86XADS)
+       default y
+       help
+         This enables support for second Ethernet on MPC885ADS and MPC86xADS 
boards.
+         The latter will use SCC1, for 885ADS you can select it below.
+
+       choice
+               prompt "Second Ethernet channel"
+               depends on MPC8xx_SECOND_ETH
+               default MPC8xx_SECOND_ETH_FEC2
+
+               config MPC8xx_SECOND_ETH_FEC2
+               bool "FEC2"
+               depends on MPC885ADS
+               help
+                 Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+                 (often 2-nd UART) will not work if this is enabled.
+
+               config MPC8xx_SECOND_ETH_SCC1
+               bool "SCC1"
+               depends on MPC86XADS
+               select MPC8xx_SCC_ENET_FIXED
+               help
+                 Enable SCC1 to serve as 2-nd Ethernet channel. Note that SMC1
+                 (often 1-nd UART) will not work if this is enabled.
+
+               config MPC8xx_SECOND_ETH_SCC3
+               bool "SCC3"
+               depends on MPC885ADS
+               help
+                 Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+                 (often 1-nd UART) will not work if this is enabled.
+
+       endchoice
+
+       config MPC8xx_SCC_ENET_FIXED
+       depends on MPC8xx_SECOND_ETH_SCC
+       default n
+       bool "Use fixed MII-less mode for SCC Ethernet"
+
+endmenu
+
  choice
        prompt "Machine Type"
        depends on 6xx || POWER3 || POWER4
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index 7c5cdab..cce6487 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -45,6 +45,8 @@ obj-$(CONFIG_SBC82xx)         += sbc82xx.o
  obj-$(CONFIG_SPRUCE)          += spruce.o
  obj-$(CONFIG_LITE5200)                += lite5200.o
  obj-$(CONFIG_EV64360)         += ev64360.o
+obj-$(CONFIG_MPC86XADS)                += mpc866ads_setup.o
+obj-$(CONFIG_MPC885ADS)                += mpc885ads_setup.o

  ifeq ($(CONFIG_SMP),y)
  obj-$(CONFIG_PPC_PMAC)                += pmac_smp.o
diff --git a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h
index a48fb8d..e1c0b1b 100644
--- a/arch/ppc/platforms/fads.h
+++ b/arch/ppc/platforms/fads.h
@@ -112,7 +112,7 @@

  /* CPM Ethernet through SCC1 or SCC2 */

-#ifdef CONFIG_SCC1_ENET                /* Probably 860 variant */
+#if defined(CONFIG_SCC1_ENET) || defined(CONFIG_MPC8xx_SECOND_ETH_SCC1)        
        /* Probably 860
variant */
  /* Bits in parallel I/O port registers that have to be set/cleared
   * to configure the pins for SCC1 use.
   * TCLK - CLK1, RCLK - CLK2.
diff --git a/arch/ppc/platforms/mpc866ads_setup.c 
b/arch/ppc/platforms/mpc866ads_setup.c
new file mode 100644
index 0000000..6ffdb0e
--- /dev/null
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -0,0 +1,290 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug at ru.mvista.com>
+ *
+ * Copyright 2005 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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/ppc_sys.h>
+#include <asm/mpc8xx.h>
+
+extern unsigned char __res[];
+
+/* access ports */
+#define setbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) |  (_v))
+#define clrbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) |  (_v))
+#define clrbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) & ~(_v))
+
+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_platform_info mpc8xx_fec_pdata[] = {
+       {
+        .rx_ring = 128,
+        .tx_ring = 16,
+        .rx_copybreak = 240,
+
+        .use_napi = 1,
+        .napi_weight = 17,
+
+        .phy_addr = 15,
+        .phy_irq = -1,
+
+        .use_rmii = 0,
+
+        .bus_info = &fec_mii_bus_info,
+        }
+};
+
+static struct fs_platform_info mpc8xx_scc_pdata = {
+       .rx_ring = 64,
+       .tx_ring = 8,
+       .rx_copybreak = 240,
+
+       .use_napi = 1,
+       .napi_weight = 17,
+
+       .phy_addr = -1,
+       .phy_irq = -1,
+
+       .bus_info = &scc_mii_bus_info,
+};
+
+static void mpc866_nonplatform_device_init(void)
+{
+       volatile cpm8xx_t *cp = cpmp;
+       unsigned *bcsr_io;
+
+       bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+       if (bcsr_io == NULL) {
+               printk(KERN_CRIT "Could not remap BCSR1\n");
+               return;
+       }
+#ifdef CONFIG_SERIAL_CPM_SMC1
+       cp->cp_simode &= ~(0xe0000000 >> 17);   /* brg1 */
+       out_be32(bcsr_io, in_be32(bcsr_io) & ~(0x80000000 >> 7));
+#else
+       out_be32(bcsr_io, in_be32(bcsr_io) | (0x80000000 >> 7));
+       cp->cp_pbpar &= ~(0x000000c0);
+       cp->cp_pbdir |= 0x000000c0;
+       cp->cp_smc[0].smc_smcmr = 0;
+       cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+       cp->cp_simode &= ~(0xe0000000 >> 1);
+       cp->cp_simode |= (0x20000000 >> 1);     /* brg2 */
+       out_be32(bcsr_io, in_be32(bcsr_io) & ~(0x80000000 >> 13));
+#else
+       out_be32(bcsr_io, in_be32(bcsr_io) | (0x80000000 >> 13));
+       cp->cp_pbpar &= ~(0x00000c00);
+       cp->cp_pbdir |= 0x00000c00;
+       cp->cp_smc[1].smc_smcmr = 0;
+       cp->cp_smc[1].smc_smce = 0;
+#endif
+       iounmap(bcsr_io);
+}
+
+static void setup_fec1_ioports(void)
+{
+       immap_t *immap = (immap_t *) IMAP_ADDR;
+
+       setbits16(immap->im_ioport.iop_pdpar, 0x1fff);
+       setbits16(immap->im_ioport.iop_pddir, 0x1fff);
+}
+
+static void setup_scc1_ioports(void)
+{
+       immap_t *immap = (immap_t *) IMAP_ADDR;
+       unsigned *bcsr_io;
+
+       bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+       if (bcsr_io == NULL) {
+               printk(KERN_CRIT "Could not remap BCSR1\n");
+               return;
+       }
+
+       /* Enable the PHY.
+        */
+       out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_ETHEN);
+
+       /* Configure port A pins for Txd and Rxd.
+        */
+       /* Disable receive and transmit in case EPPC-Bug started it.
+        */
+       setbits16(immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+       clrbits16(immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+       clrbits16(immap->im_ioport.iop_paodr, PA_ENET_TXD);
+
+       /* Configure port C pins to enable CLSN and RENA.
+        */
+       clrbits16(immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+       clrbits16(immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+       setbits16(immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+       /* Configure port A for TCLK and RCLK.
+        */
+       setbits16(immap->im_ioport.iop_papar, PA_ENET_TCLK | PA_ENET_RCLK);
+       clrbits16(immap->im_ioport.iop_padir, PA_ENET_TCLK | PA_ENET_RCLK);
+       clrbits32(immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+       clrbits32(immap->im_cpm.cp_pbdir, PB_ENET_TENA);
+
+       /* Configure Serial Interface clock routing.
+        * First, clear all SCC bits to zero, then set the ones we want.
+        */
+       clrbits32(immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+       setbits32(immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+       /* In the original SCC enet driver the following code is placed at the 
end of the
initialization */
+       setbits32(immap->im_cpm.cp_pbpar, PB_ENET_TENA);
+       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:
+               break;
+       }
+
+       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 (strcmp(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 (strcmp(pdev->name, "fsl-cpm-scc"))
+               return;
+
+       mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
+}
+
+static int mpc866ads_platform_notify(struct device *dev)
+{
+       static struct {
+               const char *bus_id;
+               void (*rtn) (struct platform_device * pdev, int idx);
+       } dev_map[] = {
+               {
+               "fsl-cpm-fec", mpc866ads_fixup_fec_enet_pdata}, {
+       "fsl-cpm-scc", mpc866ads_fixup_scc_enet_pdata},};
+       struct platform_device *pdev;
+       int i, j, idx;
+       const char *s;
+       if (dev && dev->bus_id)
+               for (i = 0; i < ARRAY_SIZE(dev_map); i++) {
+                       idx = -1;
+
+                       if ((s = strrchr(dev->bus_id, '.')) != NULL)
+                               idx = (int)simple_strtol(s + 1, NULL, 10);
+                       else
+                               s = dev->bus_id;
+                       j = s - dev->bus_id;
+                       if (!strncmp(dev->bus_id, dev_map[i].bus_id, j)) {
+                               pdev =
+                                   container_of(dev, struct platform_device,
+                                                dev);
+                               dev_map[i].rtn(pdev, idx);
+                       }
+               }
+       return 0;
+}
+
+int __init mpc866ads_init(void)
+{
+       printk(KERN_NOTICE "mpc866ads: Init\n");
+
+       mpc866_nonplatform_device_init();
+       platform_notify = mpc866ads_platform_notify;
+
+       identify_ppc_sys_by_name(BOARD_CHIP_NAME);
+
+       ppc_sys_device_remove(MPC8xx_CPM_FEC2);
+       ppc_sys_device_remove(MPC8xx_CPM_SCC3);
+       ppc_sys_device_remove(MPC8xx_CPM_SCC2);
+       ppc_sys_device_remove(MPC8xx_CPM_SCC4);
+       ppc_sys_device_remove(MPC8xx_CPM_SMC1);
+       ppc_sys_device_remove(MPC8xx_CPM_SMC2);
+
+       return 0;
+}
+
+arch_initcall(mpc866ads_init);
diff --git a/arch/ppc/platforms/mpc885ads_setup.c 
b/arch/ppc/platforms/mpc885ads_setup.c
new file mode 100644
index 0000000..37c5c7b
--- /dev/null
+++ b/arch/ppc/platforms/mpc885ads_setup.c
@@ -0,0 +1,408 @@
+/*arch/ppc/platforms/mpc885ads-setup.c
+ *
+ * Platform setup for the Freescale mpc885ads board
+ *
+ * Vitaly Bordug <vbordug at ru.mvista.com>
+ *
+ * Copyright 2005 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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/fs_enet_pd.h>
+#include <linux/mii.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ppcboot.h>
+#include <asm/8xx_immap.h>
+#include <asm/commproc.h>
+#include <asm/ppc_sys.h>
+
+extern unsigned char __res[];
+
+/* access ports */
+#define setbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) |  (_v))
+#define clrbits32(_addr, _v) out_be32(&(_addr), in_be32(&(_addr)) & ~(_v))
+
+#define setbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) |  (_v))
+#define clrbits16(_addr, _v) out_be16(&(_addr), in_be16(&(_addr)) & ~(_v))
+
+void __init mpc885ads_scc_phy_init(char);
+
+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[] = {
+       {
+        .rx_ring = 128,
+        .tx_ring = 16,
+        .rx_copybreak = 240,
+
+        .use_napi = 1,
+        .napi_weight = 17,
+
+        .phy_addr = 0,
+        .phy_irq = SIU_IRQ7,
+
+        .bus_info = &fec_mii_bus_info,
+        }, {
+            .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,
+            }
+};
+
+static struct fs_platform_info mpc8xx_scc_pdata = {
+       .rx_ring = 64,
+       .tx_ring = 8,
+       .rx_copybreak = 240,
+
+       .use_napi = 1,
+       .napi_weight = 17,
+
+       .phy_addr = 2,
+#ifdef CONFIG_MPC8xx_SCC_ENET_FIXED
+       .phy_irq = -1,
+#else
+       .phy_irq = SIU_IRQ7,
+#endif
+
+       .bus_info = &scc_mii_bus_info,
+};
+
+static void mpc885_nonplatform_device_init(void)
+{
+       volatile cpm8xx_t *cp = cpmp;
+       unsigned *bcsr_io;
+
+#ifdef CONFIG_FS_ENET
+       immap_t *immap = (immap_t *) IMAP_ADDR;
+#endif
+       bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+       if (bcsr_io == NULL) {
+               printk(KERN_CRIT "Could not remap BCSR\n");
+               return;
+       }
+#ifdef CONFIG_SERIAL_CPM_SMC1
+       cp->cp_simode &= ~(0xe0000000 >> 17);   /* brg1 */
+       out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_RS232EN_1);
+#else
+       out_be32(bcsr_io, in_be32(bcsr_io) | BCSR1_RS232EN_1);
+       cp->cp_smc[0].smc_smcmr = 0;
+       cp->cp_smc[0].smc_smce = 0;
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SMC2
+       cp->cp_simode &= ~(0xe0000000 >> 1);
+       cp->cp_simode |= (0x20000000 >> 1);     /* brg2 */
+       out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_RS232EN_2);
+#else
+       out_be32(bcsr_io, in_be32(bcsr_io) | BCSR1_RS232EN_2);
+       cp->cp_smc[1].smc_smcmr = 0;
+       cp->cp_smc[1].smc_smce = 0;
+#endif
+       iounmap(bcsr_io);
+
+#ifdef CONFIG_FS_ENET
+       /* use MDC for MII (common) */
+       setbits16(immap->im_ioport.iop_pdpar, 0x0080);
+       clrbits16(immap->im_ioport.iop_pddir, 0x0080);
+#endif
+}
+
+static void setup_fec1_ioports(void)
+{
+       immap_t *immap = (immap_t *) IMAP_ADDR;
+
+       /* configure FEC1 pins  */
+       setbits16(immap->im_ioport.iop_papar, 0xf830);
+       setbits16(immap->im_ioport.iop_padir, 0x0830);
+       clrbits16(immap->im_ioport.iop_padir, 0xf000);
+       setbits32(immap->im_cpm.cp_pbpar, 0x00001001);
+
+       clrbits32(immap->im_cpm.cp_pbdir, 0x00001001);
+       setbits16(immap->im_ioport.iop_pcpar, 0x000c);
+       clrbits16(immap->im_ioport.iop_pcdir, 0x000c);
+       setbits32(immap->im_cpm.cp_pepar, 0x00000003);
+
+       setbits32(immap->im_cpm.cp_pedir, 0x00000003);
+       clrbits32(immap->im_cpm.cp_peso, 0x00000003);
+       clrbits32(immap->im_cpm.cp_cptr, 0x00000100);
+}
+
+static void setup_fec2_ioports(void)
+{
+       immap_t *immap = (immap_t *) IMAP_ADDR;
+
+       /* 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);
+       clrbits32(immap->im_cpm.cp_cptr, 0x00000080);
+}
+
+static void setup_scc3_ioports(void)
+{
+       immap_t *immap = (immap_t *) IMAP_ADDR;
+       unsigned *bcsr_io;
+
+       bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
+
+       if (bcsr_io == NULL) {
+               printk(KERN_CRIT "Could not remap BCSR\n");
+               return;
+       }
+
+       /* Enable the PHY.
+        */
+       out_be32(bcsr_io + 4, in_be32(bcsr_io + 4) | BCSR4_ETH10_RST);
+
+       /* Configure port A pins for Txd and Rxd.
+        */
+       setbits16(immap->im_ioport.iop_papar, PA_ENET_RXD | PA_ENET_TXD);
+       clrbits16(immap->im_ioport.iop_padir, PA_ENET_RXD | PA_ENET_TXD);
+
+       /* Configure port C pins to enable CLSN and RENA.
+        */
+       clrbits16(immap->im_ioport.iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
+       clrbits16(immap->im_ioport.iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
+       setbits16(immap->im_ioport.iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
+
+       /* Configure port E for TCLK and RCLK.
+        */
+       setbits32(immap->im_cpm.cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
+       clrbits32(immap->im_cpm.cp_pepar, PE_ENET_TENA);
+       clrbits32(immap->im_cpm.cp_pedir,
+                 PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
+       clrbits32(immap->im_cpm.cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
+       setbits32(immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+       /* Configure Serial Interface clock routing.
+        * First, clear all SCC bits to zero, then set the ones we want.
+        */
+       clrbits32(immap->im_cpm.cp_sicr, SICR_ENET_MASK);
+       setbits32(immap->im_cpm.cp_sicr, SICR_ENET_CLKRT);
+
+       /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
+        */
+       immap->im_cpm.cp_smc[0].smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+       /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex 
mode
+        * by H/W setting after reset. SCC ethernet controller support only 
half duplex.
+        * This discrepancy of modes causes a lot of carrier lost errors.
+        */
+
+       /* In the original SCC enet driver the following code is placed at the 
end of the
initialization */
+       setbits32(immap->im_cpm.cp_pepar, PE_ENET_TENA);
+       clrbits32(immap->im_cpm.cp_pedir, PE_ENET_TENA);
+       setbits32(immap->im_cpm.cp_peso, PE_ENET_TENA);
+
+       out_be32(bcsr_io + 1, in_be32(bcsr_io + 1) | BCSR1_ETHEN);
+       iounmap(bcsr_io);
+}
+
+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;
+       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_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:
+               break;
+       }
+
+       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 mpc885ads_fixup_fec_enet_pdata(struct platform_device *pdev,
+                                                 int idx)
+{
+       /* This is for FEC devices only */
+       if (!strstr(pdev->name, "fsl-cpm-fec"))
+               return;
+       mpc885ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1);
+}
+
+static void __init mpc885ads_fixup_scc_enet_pdata(struct platform_device *pdev,
+                                                 int idx)
+{
+       /* This is for SCC devices only */
+       if (!strstr(pdev->name, "fsl-cpm-scc"))
+               return;
+
+       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 int mpc885ads_platform_notify(struct device *dev)
+{
+       static struct {
+               const char *bus_id;
+               void (*rtn) (struct platform_device * pdev, int idx);
+       } dev_map[] = {
+               {
+               "fsl-cpm-fec", mpc885ads_fixup_fec_enet_pdata}, {
+       "fsl-cpm-scc", mpc885ads_fixup_scc_enet_pdata},};
+       struct platform_device *pdev;
+       int i, j, idx;
+       const char *s;
+       if (dev && dev->bus_id)
+               for (i = 0; i < ARRAY_SIZE(dev_map); i++) {
+                       idx = -1;
+
+                       if ((s = strrchr(dev->bus_id, '.')) != NULL)
+                               idx = (int)simple_strtol(s + 1, NULL, 10);
+                       else
+                               s = dev->bus_id;
+                       j = s - dev->bus_id;
+                       if (!strncmp(dev->bus_id, dev_map[i].bus_id, j)) {
+                               pdev =
+                                   container_of(dev, struct platform_device,
+                                                dev);
+                               dev_map[i].rtn(pdev, idx);
+                       }
+               }
+       return 0;
+}
+
+int __init mpc885ads_init(void)
+{
+       printk(KERN_NOTICE "mpc885ads: Init\n");
+
+       mpc885_nonplatform_device_init();
+       platform_notify = mpc885ads_platform_notify;
+
+       identify_ppc_sys_by_name(BOARD_CHIP_NAME);
+
+#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
+       ppc_sys_device_remove(MPC8xx_CPM_FEC2);
+#endif
+#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2
+       ppc_sys_device_remove(MPC8xx_CPM_SCC3);
+#endif
+
+       ppc_sys_device_remove(MPC8xx_CPM_SCC1);
+       ppc_sys_device_remove(MPC8xx_CPM_SCC2);
+       ppc_sys_device_remove(MPC8xx_CPM_SCC4);
+       ppc_sys_device_remove(MPC8xx_CPM_SMC1);
+       ppc_sys_device_remove(MPC8xx_CPM_SMC2);
+
+       return 0;
+}
+
+arch_initcall(mpc885ads_init);
---
Sincerely,
Vitaly




Reply via email to