From: prafulla_wadaskar <prafu...@marvell.com>

Chips supprted:-
1. 88E61XX 6 port gbe swtich with 5 integrated PHYs
2. 88E6061 6 port fe swtich with 5 integrated PHYs
3. 88E1116 gbe transceiver

Contributors:
Yotam Admon <yo...@marvell.com>
Michael Blostein <michae...@marvell.com

Signed-off-by: prafulla_wadaskar <prafu...@marvell.com>
Reviewed by: Ronen Shitrit <rshit...@marvell.com>
---
 board/Marvell/common/mv88e1116.c |   72 +++++++
 board/Marvell/common/mv88e60xx.c |  409 +++++++++++++++++++++++++++++++++++++
 board/Marvell/common/mv88e61xx.c |  414 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 895 insertions(+), 0 deletions(-)
 create mode 100644 board/Marvell/common/mv88e1116.c
 create mode 100644 board/Marvell/common/mv88e60xx.c
 create mode 100644 board/Marvell/common/mv88e61xx.c

diff --git a/board/Marvell/common/mv88e1116.c b/board/Marvell/common/mv88e1116.c
new file mode 100644
index 0000000..87ec550
--- /dev/null
+++ b/board/Marvell/common/mv88e1116.c
@@ -0,0 +1,72 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Prafulla Wadaskar <prafu...@marvell.com>
+ *
+ * Contributors
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef MV88E1116_DEBUG
+#define MV88E1116_DEBUG 0
+#endif
+#define DEBUG_PRINT    MV88E1116_DEBUG
+
+#include <common.h>
+#include <debug_prints.h>
+#include "../common/ppc_error_no.h"
+
+#if defined (CONFIG_PHY_88E1116)
+
+/*
+ * Marvell 88E1116 PHY initialization
+ */
+void mv_phy_88e1116_init(u32 eth_port_num)
+{
+       u16 reg;
+       u32 smi_dev_addr;
+
+       debug_print_ftrace();
+       smi_dev_addr = KW_REG_READ(KW_ETH_PHY_ADDR_REG(eth_port_num));
+
+       /* Leds link and activity */
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 22, 0x3);
+       eth_smi_reg_read(eth_port_num, smi_dev_addr, 16, &reg);
+       reg &= ~0xf;
+       reg |= 0x1;
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 16, reg);
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 22, 0x0);
+
+       /* Set RGMII delay */
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 22, 2);
+       eth_smi_reg_read(eth_port_num, smi_dev_addr, 21, &reg);
+       reg |= (BIT5 | BIT4);
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 21, reg);
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 22, 0);
+
+       /* reset the phy */
+       eth_smi_reg_read(eth_port_num, smi_dev_addr, 0, &reg);
+       reg |= BIT15;
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 0, reg);
+
+       info_print("88E1116 Initialized");
+}
+
+#endif /* CONFIG_PHY_88E61XX */
diff --git a/board/Marvell/common/mv88e60xx.c b/board/Marvell/common/mv88e60xx.c
new file mode 100644
index 0000000..6034f7b
--- /dev/null
+++ b/board/Marvell/common/mv88e60xx.c
@@ -0,0 +1,409 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Prafulla Wadaskar <prafu...@marvell.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef MV88E60XX_DEBUG
+#define MV88E60XX_DEBUG 0
+#endif
+#define DEBUG_PRINT    MV88E60XX_DEBUG
+
+#include <common.h>
+#include <debug_prints.h>
+#include "../common/ppc_error_no.h"
+#include <command.h>
+#include <environment.h>
+#include <watchdog.h>
+#include <serial.h>
+#include <linux/stddef.h>
+#include <asm/byteorder.h>
+#if defined(CONFIG_CMD_NET)
+#include <net.h>
+#endif
+
+#if defined (CONFIG_SWITCH_88E60XX)
+
+/* CPU port can be configured in board header file */
+#if defined (CONFIG_SWITCH_88E60XX_CPU_PORT)
+#define MV88E60XX_CPU_PORT      CONFIG_SWITCH_88E60XX_CPU_PORT
+#else
+#define MV88E60XX_CPU_PORT      0x5
+#endif
+/* Enabled ports can be configured in board header file */
+#if defined (CONFIG_SWITCH_88E60XX_ENABLED_PORTS)
+#define MV88E60XX_ENABLED_PORTS CONFIG_SWITCH_88E60XX_ENABLED_PORTS
+#else
+#define MV88E60XX_ENABLED_PORTS (BIT0 | BIT1 | BIT2 | \
+                                 BIT3 | BIT4 | BIT5)
+#endif
+
+#ifdef CONFIG_SWITCH_MV88E6061
+#define MV88E60XX_NAME                                  "88E6061"
+#else
+#define MV88E60XX_NAME                                  "88E60xx"
+#endif
+#define MV88E60XX_PHY_TIMEOUT                           100000
+#define MV88E60XX_MAX_PORTS_NUM                         0x6
+
+#define MV88E60XX_PORT_STATUS_REG                       0x1
+#define MV88E60XX_PORT_CONTROL_REG                      0x4
+#define MV88E60XX_PORT_VMAP_REG                         0x6
+#define MV88E60XX_PORT_VID_REG                          0x7
+
+#define MV88E60XX_PHY_SPEC_CONTROL_REG                  0x10
+#define MV88E60XX_PHY_CONTROL_REG                       0x00
+
+#define MV88E60XX_PHY_OFFSET                            0x10
+#define MV88E60XX_PORTS_OFFSET                          0x18
+#define MV88E60XX_SMI_PHY_COMMAND                       0x18
+#define MV88E60XX_SMI_PHY_DATA                          0x19
+#define MV88E60XX_GLOBAL_2_REG_DEV_ADDR                 0x1C
+
+#define MV88E60XX_PORT_STATUS_BIT_LINKUP                BIT2
+
+#define mv_sw_eth_phy_reg_write eth_smi_reg_write
+#define mv_sw_eth_phy_reg_read eth_smi_reg_read
+
+static void mv_switch_88e60xx_vlan_init(u32 eth_port_num,
+                                       u32 switch_cpu_port,
+                                       u32 switch_max_ports_num,
+                                       u32 switch_ports_ofs,
+                                       u32 switch_enabled_ports_mask)
+{
+       u32 prt;
+       u16 reg;
+
+       debug_print_ftrace();
+       /* be sure all ports are disabled */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+               mv_sw_eth_phy_reg_read(eth_port_num, (switch_ports_ofs + prt),
+                                      MV88E60XX_PORT_CONTROL_REG, &reg);
+               reg &= ~0x3;
+               mv_sw_eth_phy_reg_write(eth_port_num, (switch_ports_ofs + prt),
+                                       MV88E60XX_PORT_CONTROL_REG, reg);
+       }
+       /* Set CPU port VID to 0x1 */
+       mv_sw_eth_phy_reg_read(eth_port_num,
+                              (switch_ports_ofs + switch_cpu_port),
+                              MV88E60XX_PORT_VID_REG, &reg);
+       reg &= ~0xfff;
+       reg |= 0x1;
+       mv_sw_eth_phy_reg_write(eth_port_num,
+                               (switch_ports_ofs + switch_cpu_port),
+                               MV88E60XX_PORT_VID_REG, reg);
+       /* Setting  Port default priority for all ports to zero */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+               mv_sw_eth_phy_reg_read(eth_port_num, (switch_ports_ofs + prt),
+                                      MV88E60XX_PORT_VID_REG, &reg);
+               reg &= ~0xc000;
+               mv_sw_eth_phy_reg_write(eth_port_num, (switch_ports_ofs + prt),
+                                       MV88E60XX_PORT_VID_REG, reg);
+       }
+       /* Setting VID and VID map for all ports except CPU port */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+               /* only for enabled ports */
+               if ((1 << prt) & switch_enabled_ports_mask) {
+                       /* skip CPU port */
+                       if (prt == switch_cpu_port)
+                               continue;
+
+                       /*
+                        *  set Ports VLAN Mapping.
+                        *      port prt <--> MV88E60XX_CPU_PORT VLAN #prt+1.
+                        */
+
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E60XX_PORT_VID_REG, &reg);
+                       reg &= ~0x0fff;
+                       reg |= (prt + 1);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E60XX_PORT_VID_REG, reg);
+
+                       /* Set Vlan map table for all ports to send only to 
MV88E60XX_CPU_PORT */
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E60XX_PORT_VMAP_REG, &reg);
+                       reg &= ~((1 << switch_max_ports_num) - 1);
+                       reg |= (1 << switch_cpu_port);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E60XX_PORT_VMAP_REG, reg);
+               }
+       }
+       /* Set Vlan map table for MV88E60XX_CPU_PORT to see all ports */
+       mv_sw_eth_phy_reg_read(eth_port_num,
+                              (switch_ports_ofs + switch_cpu_port),
+                              MV88E60XX_PORT_VMAP_REG, &reg);
+       reg &= ~((1 << switch_max_ports_num) - 1);
+       reg |= switch_enabled_ports_mask & ~(1 << switch_cpu_port);
+       mv_sw_eth_phy_reg_write(eth_port_num,
+                               (switch_ports_ofs + switch_cpu_port),
+                               MV88E60XX_PORT_VMAP_REG, reg);
+
+       /*enable only appropriate ports to forwarding mode - and disable the 
others */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+
+               if ((1 << prt) & switch_enabled_ports_mask) {
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E60XX_PORT_CONTROL_REG,
+                                              &reg);
+                       reg |= 0x3;
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E60XX_PORT_CONTROL_REG,
+                                               reg);
+               } else {
+                       /* Disable port */
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E60XX_PORT_CONTROL_REG,
+                                              &reg);
+                       reg &= ~0x3;
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E60XX_PORT_CONTROL_REG,
+                                               reg);
+               }
+       }
+}
+
+/*
+ * Marvell 88E60XX Switch initialization
+ */
+int mv_switch_88e60xx_init(u32 eth_port_num)
+{
+       u32 prt;
+       u16 reg;
+       volatile u32 timeout;
+
+       debug_print_ftrace();
+
+       /* Init vlan */
+       mv_switch_88e60xx_vlan_init(eth_port_num, MV88E60XX_CPU_PORT,
+                                   MV88E60XX_MAX_PORTS_NUM,
+                                   MV88E60XX_PORTS_OFFSET,
+                                   MV88E60XX_ENABLED_PORTS);
+       for (prt = 0; prt < MV88E60XX_MAX_PORTS_NUM; prt++) {
+               if (prt != MV88E60XX_CPU_PORT) {
+                       /*Enable Phy power up */
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (MV88E60XX_PHY_OFFSET + prt),
+                                               MV88E60XX_PHY_CONTROL_REG,
+                                               0xA100);
+               }
+               /*Enable port */
+               mv_sw_eth_phy_reg_write(eth_port_num,
+                                       MV88E60XX_PORTS_OFFSET + prt, 4, 0x17f);
+       }
+       /*Force CPU port to RGMII FDX 100Base */
+       mv_sw_eth_phy_reg_write(eth_port_num,
+                               MV88E60XX_PORTS_OFFSET + MV88E60XX_CPU_PORT, 1,
+                               0x3d);
+
+       info_print(MV88E60XX_NAME " Initialized");
+       return 0;
+}
+
+#if defined(CONFIG_CMD_SMIRW)
+int smi_read_command(u32 smiaddr, u32 regaddr, u32 page)
+{
+       int prt = page;
+       u32 value;
+
+       mv_sw_eth_phy_reg_read(0, smiaddr, regaddr, &value);
+       printf("smiread(smiaddr %x, regaddr %x, page %d)=%04x\n", smiaddr,
+              regaddr, page, (u16) value);
+       return 0;
+}
+
+int smi_write_command(u32 smiaddr, u32 regaddr, u32 page, u32 value)
+{
+       int prt = page;
+       u32 page_backup = 0;
+
+       mv_sw_eth_phy_reg_write(0, smiaddr, regaddr, value);
+       printf("smiwrite(smiaddr %x, regaddr %x, page %d) written =%04x\n",
+              smiaddr, regaddr, page, value);
+       return 0;
+}
+
+/*
+ * "smi read [smiaddr] [regaddr] [page]\n"
+ * "    - read smi register command\n"
+ * "smi write [smiaddr] [regaddr] [value] [page]\n"
+ * "    - write <value> to <regaddr> register command\n"
+ */
+int do_smi(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+       u32 smiaddr = 0, regaddr = 0, value = 0, page = 0, size = 0;
+       char cmd = ' ';
+
+       if (argc > 1)
+               cmd = argv[1][0];
+
+       switch (cmd) {
+       case 'r':               /* read */
+               if (argc > 2)
+                       smiaddr = simple_strtoul(argv[2], NULL, 16);
+               if (argc > 3)
+                       regaddr = simple_strtoul(argv[3], NULL, 16);
+               if (argc > 4)
+                       page = simple_strtoul(argv[4], NULL, 16);
+               break;
+       case 'w':               /* write */
+               if (argc < 4)
+                       goto usage;
+               smiaddr = simple_strtoul(argv[2], NULL, 16);
+               regaddr = simple_strtoul(argv[3], NULL, 16);
+               value = simple_strtoul(argv[4], NULL, 16);
+               if (argc > 5)
+                       page = simple_strtoul(argv[5], NULL, 16);
+               break;
+       default:
+             usage:
+               printf("Usage:\n%s\n", cmdtp->usage);
+               return 1;
+       }
+
+       switch (argv[1][0]) {
+       case 'r':               /* read */
+               smi_read_command(smiaddr, regaddr, page);
+               return 0;
+       case 'w':               /* write */
+               smi_write_command(smiaddr, regaddr, page, value);
+               return 0;
+       }
+       return 1;
+}
+
+U_BOOT_CMD(smi, CONFIG_SYS_MAXARGS, 1, do_smi,
+          "smi - isues read/write command on smi for switch registers\n",
+          "smi read [smiaddr] [regaddr] [page]\n"
+          "    - read smi register command\n"
+          "smi write [smiaddr] [regaddr] [value] [page]\n"
+          "    - write <value> to <regaddr> register command\n"
+          "    - run the commands in the environment variable(s) 'var'\n");
+
+#endif /* CONFIG_CMD_SMIRW */
+
+#if defined(CONFIG_CMD_DUMP60XXPHY)
+static void phy_busywait(u32 eth_port_num)
+{
+       u32 timeout;
+       u16 reg;
+
+       timeout = MV88E60XX_PHY_TIMEOUT;
+       do {
+               mv_sw_eth_phy_reg_read(eth_port_num,
+                                      MV88E60XX_GLOBAL_2_REG_DEV_ADDR,
+                                      MV88E60XX_SMI_PHY_COMMAND, &reg);
+               if (timeout-- == 0) {
+                       error_print("SMI busy timeout");
+                       return -1;
+               }
+       } while (reg & BIT28);  /* busy mask */
+}
+
+int do_dump60xxphy(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+#define SMI_CMD_BUSY_OFFSET                                    15
+#define SMI_CMD_MODE_OFFSET                                    12
+#define SMI_CMD_OP_OFFSET                                      10
+#define SMI_CMD_ADDR_OFFSET                                    5
+
+       int page, i, prt;
+       int eth_port_num = 0;
+       u32 reg;
+
+       /* set page address to 3 */
+       prt = 0;
+       for (page = 0; page < 7; page++) {
+               if (page == 1)
+                       continue;
+               if (page == 4)
+                       continue;
+               phy_busywait(eth_port_num);
+               mv_sw_eth_phy_reg_write(eth_port_num,
+                                       MV88E60XX_GLOBAL_2_REG_DEV_ADDR,
+                                       MV88E60XX_SMI_PHY_DATA, page);
+
+               phy_busywait(eth_port_num);
+               mv_sw_eth_phy_reg_write(eth_port_num,
+                                       MV88E60XX_GLOBAL_2_REG_DEV_ADDR,
+                                       MV88E60XX_SMI_PHY_COMMAND,
+                                       (1 << SMI_CMD_BUSY_OFFSET | 1 <<
+                                        SMI_CMD_MODE_OFFSET | 1 <<
+                                        SMI_CMD_OP_OFFSET | prt <<
+                                        SMI_CMD_ADDR_OFFSET | 22));
+
+               /* read and display phy registers */
+               for (i = 0; i < 29; i++) {
+                       if (page != 0) {
+                               if (i < 16)
+                                       continue;
+                               if (i == 22)
+                                       continue;
+                       }
+                       phy_busywait(eth_port_num);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               MV88E60XX_GLOBAL_2_REG_DEV_ADDR,
+                                               MV88E60XX_SMI_PHY_COMMAND,
+                                               (1 << SMI_CMD_BUSY_OFFSET | 1 <<
+                                                SMI_CMD_MODE_OFFSET | 2 <<
+                                                SMI_CMD_OP_OFFSET | prt <<
+                                                SMI_CMD_ADDR_OFFSET | i));
+
+                       phy_busywait(eth_port_num);
+                       reg = 0x0;
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              MV88E60XX_GLOBAL_2_REG_DEV_ADDR,
+                                              MV88E60XX_SMI_PHY_DATA, &reg);
+
+                       printf("page %d reg %02d = %04x\n", page, i, (u16) reg);
+               }
+       }
+
+       /* restore page address to zero */
+       reg = 0;
+       phy_busywait(eth_port_num);
+       mv_sw_eth_phy_reg_write(eth_port_num, MV88E60XX_GLOBAL_2_REG_DEV_ADDR,
+                               MV88E60XX_SMI_PHY_DATA, reg);
+       phy_busywait(eth_port_num);
+       mv_sw_eth_phy_reg_write(eth_port_num, MV88E60XX_GLOBAL_2_REG_DEV_ADDR,
+                               MV88E60XX_SMI_PHY_COMMAND,
+                               (1 << SMI_CMD_BUSY_OFFSET | 1 <<
+                                SMI_CMD_MODE_OFFSET | 1 << SMI_CMD_OP_OFFSET |
+                                prt << SMI_CMD_ADDR_OFFSET | 22));
+
+       return 0;
+}
+
+U_BOOT_CMD(dump60xxphy, CONFIG_SYS_MAXARGS, 1, do_dump60xxphy,
+          "dump60xxphy - dump 88360xx registers\n",
+          "var [...]\n"
+          "    - run the commands in the environment variable(s) 'var'\n");
+#endif /* CONFIG_CMD_DUMP60XXPHY */
+
+#endif /* CONFIG_SWITCH_88E60XX */
diff --git a/board/Marvell/common/mv88e61xx.c b/board/Marvell/common/mv88e61xx.c
new file mode 100644
index 0000000..72a58eb
--- /dev/null
+++ b/board/Marvell/common/mv88e61xx.c
@@ -0,0 +1,414 @@
+/*
+ * (C) Copyright 2009
+ * Marvell Semiconductor <www.marvell.com>
+ * Prafulla Wadaskar <prafu...@marvell.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef MV88E61XX_DEBUG
+#define MV88E61XX_DEBUG 0
+#endif
+#define DEBUG_PRINT    MV88E61XX_DEBUG
+
+#include <common.h>
+#include <debug_prints.h>
+#include "../common/ppc_error_no.h"
+#include <command.h>
+#include <environment.h>
+#include <watchdog.h>
+#include <serial.h>
+#include <linux/stddef.h>
+#include <asm/byteorder.h>
+#if defined(CONFIG_CMD_NET)
+#include <net.h>
+#endif
+
+#if defined (CONFIG_SWITCH_88E61XX)
+
+/* CPU port can be configured in board header file */
+#if defined (CONFIG_SWITCH_88E61XX_CPU_PORT)
+#define MV88E61XX_CPU_PORT      CONFIG_SWITCH_88E61XX_CPU_PORT
+#else
+#define MV88E61XX_CPU_PORT      0x5
+#endif
+/* Enabled ports can be configured in board header file */
+#if defined (CONFIG_SWITCH_88E61XX_ENABLED_PORTS)
+#define MV88E61XX_ENABLED_PORTS CONFIG_SWITCH_88E61XX_ENABLED_PORTS
+#else
+#define MV88E61XX_ENABLED_PORTS (BIT0 | BIT1 | BIT2 | \
+                                 BIT3 | BIT4 | BIT5)
+#endif
+
+#define MV88E61XX_NAME                                  "88E6165"
+#define MV88E61XX_PHY_TIMEOUT                           100000
+#define MV88E61XX_MAX_PORTS_NUM                         0x6
+
+#define MV88E61XX_PORT_STATUS_REG                       0x1
+#define MV88E61XX_PORT_CONTROL_REG                      0x4
+#define MV88E61XX_PORT_VMAP_REG                         0x6
+#define MV88E61XX_PORT_VID_REG                          0x7
+
+#define MV88E61XX_PORTS_OFFSET                          0x10
+#define MV88E61XX_SMI_PHY_COMMAND                       0x18
+#define MV88E61XX_SMI_PHY_DATA                          0x19
+#define MV88E61XX_GLOBAL_2_REG_DEV_ADDR                 0x1C
+
+#define MV88E61XX_PORT_STATUS_BIT_LINKUP                BIT2
+
+/* Chip Address mode
+ * The Switch support two modes of operation
+ * 1. single chip mode and
+ * 2. Multi-chip mode
+ * Refer chip documentation for more details
+ *
+ * By default single chip mode is configured
+ * multichip mode operation can be configured in board header
+ */
+#ifndef CONFIG_SWITCH_88E61XX_MULTI_CHIP_ADDR_MODE
+#define mv_sw_eth_phy_reg_write eth_smi_reg_write
+#define mv_sw_eth_phy_reg_read eth_smi_reg_read
+#else
+void mv_sw_eth_phy_reg_write(u32 eth_port_num, u32 phy_adr, u32 reg_ofs,
+                            u16 data)
+{
+       u16 reg;
+       u32 smi_dev_addr;
+
+       smi_dev_addr = KW_REG_READ(KW_ETH_PHY_ADDR_REG(eth_port_num));
+       do {
+               eth_smi_reg_read(eth_port_num, smi_dev_addr, 0x0, &reg);
+       } while ((reg & BIT15));
+       /* Poll till SMIBusy bit is clear */
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 0x1, data);
+       /* Write data to Switch indirect data register */
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 0x0,
+                         reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15);
+       /* Write command to Switch indirect command register (write) */
+}
+
+void mv_sw_eth_phy_reg_read(u32 eth_port_num, u32 phy_adr, u32 reg_ofs,
+                           u16 * data)
+{
+       u16 reg;
+       u32 smi_dev_addr;
+
+       smi_dev_addr = KW_REG_READ(KW_ETH_PHY_ADDR_REG(eth_port_num));
+       do {
+               eth_smi_reg_read(eth_port_num, smi_dev_addr, 0x0, &reg);
+       } while ((reg & BIT15));
+       /* Poll till SMIBusy bit is clear */
+       eth_smi_reg_write(eth_port_num, smi_dev_addr, 0x0,
+                         reg_ofs | (phy_adr << 5) | BIT10 | BIT12 | BIT15);
+       /* Write command to Switch indirect command register (read) */
+       do {
+               eth_smi_reg_read(eth_port_num, smi_dev_addr, 0x0, &reg);
+       } while ((reg & BIT15));
+       /* Poll till SMIBusy bit is clear */
+       eth_smi_reg_read(eth_port_num, smi_dev_addr, 0x1, (u16 *) & data);
+       /* Read data from Switch indirect data register */
+}
+#endif
+
+static void mv_switch_88e61xx_vlan_init(u32 eth_port_num,
+                                       u32 switch_cpu_port,
+                                       u32 switch_max_ports_num,
+                                       u32 switch_ports_ofs,
+                                       u32 switch_enabled_ports_mask)
+{
+       u32 prt;
+       u16 reg;
+
+       debug_print_ftrace();
+       /* be sure all ports are disabled */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+               mv_sw_eth_phy_reg_read(eth_port_num, (switch_ports_ofs + prt),
+                                      MV88E61XX_PORT_CONTROL_REG, &reg);
+               reg &= ~0x3;
+               mv_sw_eth_phy_reg_write(eth_port_num, (switch_ports_ofs + prt),
+                                       MV88E61XX_PORT_CONTROL_REG, reg);
+       }
+       /* Set CPU port VID to 0x1 */
+       mv_sw_eth_phy_reg_read(eth_port_num,
+                              (switch_ports_ofs + switch_cpu_port),
+                              MV88E61XX_PORT_VID_REG, &reg);
+       reg &= ~0xfff;
+       reg |= 0x1;
+       mv_sw_eth_phy_reg_write(eth_port_num,
+                               (switch_ports_ofs + switch_cpu_port),
+                               MV88E61XX_PORT_VID_REG, reg);
+
+       /* Setting  Port default priority for all ports to zero */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+               mv_sw_eth_phy_reg_read(eth_port_num, (switch_ports_ofs + prt),
+                                      MV88E61XX_PORT_VID_REG, &reg);
+               reg &= ~0xc000;
+               mv_sw_eth_phy_reg_write(eth_port_num, (switch_ports_ofs + prt),
+                                       MV88E61XX_PORT_VID_REG, reg);
+       }
+       /* Setting VID and VID map for all ports except CPU port */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+               /* only for enabled ports */
+               if ((1 << prt) & switch_enabled_ports_mask) {
+                       /* skip CPU port */
+                       if (prt == switch_cpu_port)
+                               continue;
+
+                       /*
+                        *  set Ports VLAN Mapping.
+                        *      port prt <--> MV88E61XX_CPU_PORT VLAN #prt+1.
+                        */
+
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E61XX_PORT_VID_REG, &reg);
+                       reg &= ~0x0fff;
+                       reg |= (prt + 1);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E61XX_PORT_VID_REG, reg);
+
+                       /* Set Vlan map table for all ports to send only to 
MV88E61XX_CPU_PORT */
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E61XX_PORT_VMAP_REG, &reg);
+                       reg &= ~((1 << switch_max_ports_num) - 1);
+                       reg |= (1 << switch_cpu_port);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E61XX_PORT_VMAP_REG, reg);
+               }
+       }
+       /* Set Vlan map table for MV88E61XX_CPU_PORT to see all ports */
+       mv_sw_eth_phy_reg_read(eth_port_num,
+                              (switch_ports_ofs + switch_cpu_port),
+                              MV88E61XX_PORT_VMAP_REG, &reg);
+       reg &= ~((1 << switch_max_ports_num) - 1);
+       reg |= switch_enabled_ports_mask & ~(1 << switch_cpu_port);
+       mv_sw_eth_phy_reg_write(eth_port_num,
+                               (switch_ports_ofs + switch_cpu_port),
+                               MV88E61XX_PORT_VMAP_REG, reg);
+
+       /*enable only appropriate ports to forwarding mode - and disable the 
others */
+       for (prt = 0; prt < switch_max_ports_num; prt++) {
+               if ((1 << prt) & switch_enabled_ports_mask) {
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E61XX_PORT_CONTROL_REG,
+                                              &reg);
+                       reg |= 0x3;
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E61XX_PORT_CONTROL_REG,
+                                               reg);
+               } else {
+                       /* Disable port */
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              (switch_ports_ofs + prt),
+                                              MV88E61XX_PORT_CONTROL_REG,
+                                              &reg);
+                       reg &= ~0x3;
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               (switch_ports_ofs + prt),
+                                               MV88E61XX_PORT_CONTROL_REG,
+                                               reg);
+               }
+       }
+}
+
+/*
+ * Marvell 88E61XX Switch initialization
+ */
+int mv_switch_88e61xx_init(u32 eth_port_num)
+{
+       u32 prt;
+       u16 reg;
+       volatile u32 timeout;
+
+       debug_print_ftrace();
+       /* Init vlan */
+       mv_switch_88e61xx_vlan_init(eth_port_num, MV88E61XX_CPU_PORT,
+                                   MV88E61XX_MAX_PORTS_NUM,
+                                   MV88E61XX_PORTS_OFFSET,
+                                   MV88E61XX_ENABLED_PORTS);
+
+       /* Enable RGMII delay on Tx and Rx for CPU port */
+       mv_sw_eth_phy_reg_write(eth_port_num, 0x14, 0x1a, 0x81e7);
+       mv_sw_eth_phy_reg_read(eth_port_num, 0x15, 0x1a, &reg);
+       mv_sw_eth_phy_reg_write(eth_port_num, 0x15, 0x1a, 0x18);
+       mv_sw_eth_phy_reg_write(eth_port_num, 0x14, 0x1a, 0xc1e7);
+
+       for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
+               if (prt != MV88E61XX_CPU_PORT) {
+                       /*Enable Phy power up */
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                               MV88E61XX_SMI_PHY_DATA, 0x3360);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                               MV88E61XX_SMI_PHY_COMMAND,
+                                               (0x9410 | (prt << 5)));
+
+                       /*Make sure SMIBusy bit cleared before another SMI 
operation can take place */
+                       timeout = MV88E61XX_PHY_TIMEOUT;
+                       do {
+                               mv_sw_eth_phy_reg_read(eth_port_num,
+                                                      
MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                                      
MV88E61XX_SMI_PHY_COMMAND,
+                                                      &reg);
+                               if (timeout-- == 0) {
+                                       error_print("SMI busy timeout");
+                                       return -1;
+                               }
+                       } while (reg & BIT28);  /* busy mask */
+
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                               MV88E61XX_SMI_PHY_DATA, 0x1140);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                               MV88E61XX_SMI_PHY_COMMAND,
+                                               (0x9400 | (prt << 5)));
+
+                       /*Make sure SMIBusy bit cleared before another SMI 
operation can take place */
+                       timeout = MV88E61XX_PHY_TIMEOUT;
+                       do {
+                               mv_sw_eth_phy_reg_read(eth_port_num,
+                                                      
MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                                      
MV88E61XX_SMI_PHY_COMMAND,
+                                                      &reg);
+                               if (timeout-- == 0) {
+                                       error_print("SMI busy timeout");
+                                       return -1;
+                               }
+                       } while (reg & BIT28);  /* busy mask */
+               }
+
+               /*Enable port */
+               mv_sw_eth_phy_reg_write(eth_port_num,
+                                       MV88E61XX_PORTS_OFFSET + prt, 4, 0x7f);
+       }
+       /*Force CPU port to RGMII FDX 1000Base */
+       mv_sw_eth_phy_reg_write(eth_port_num,
+                               MV88E61XX_PORTS_OFFSET + MV88E61XX_CPU_PORT, 1,
+                               0x3e);
+
+       info_print(MV88E61XX_NAME " Initialized");
+       return 0;
+}
+
+#if defined(CONFIG_CMD_DUMP61XXPHY)
+static void phy_busywait(u32 eth_port_num)
+{
+       u32 timeout;
+       u16 reg;
+
+       timeout = MV88E61XX_PHY_TIMEOUT;
+       do {
+               mv_sw_eth_phy_reg_read(eth_port_num,
+                                      MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                      MV88E61XX_SMI_PHY_COMMAND, &reg);
+               if (timeout-- == 0) {
+                       error_print("SMI busy timeout");
+                       return -1;
+               }
+       } while (reg & BIT28);  /* busy mask */
+}
+
+int do_dump61xxphy(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+#define SMI_CMD_BUSY_OFFSET                                    15
+#define SMI_CMD_MODE_OFFSET                                    12
+#define SMI_CMD_OP_OFFSET                                      10
+#define SMI_CMD_ADDR_OFFSET                                    5
+
+       int page, i, prt;
+       int eth_port_num = 0;
+       u32 reg;
+
+       /* set page address to 3 */
+       prt = 0;
+       for (page = 0; page < 7; page++) {
+               if (page == 1)
+                       continue;
+               if (page == 4)
+                       continue;
+               phy_busywait(eth_port_num);
+               mv_sw_eth_phy_reg_write(eth_port_num,
+                                       MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                       MV88E61XX_SMI_PHY_DATA, page);
+
+               phy_busywait(eth_port_num);
+               mv_sw_eth_phy_reg_write(eth_port_num,
+                                       MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                       MV88E61XX_SMI_PHY_COMMAND,
+                                       (1 << SMI_CMD_BUSY_OFFSET | 1 <<
+                                        SMI_CMD_MODE_OFFSET | 1 <<
+                                        SMI_CMD_OP_OFFSET | prt <<
+                                        SMI_CMD_ADDR_OFFSET | 22));
+
+               /* read and display phy registers */
+               for (i = 0; i < 29; i++) {
+                       if (page != 0) {
+                               if (i < 16)
+                                       continue;
+                               if (i == 22)
+                                       continue;
+                       }
+                       phy_busywait(eth_port_num);
+                       mv_sw_eth_phy_reg_write(eth_port_num,
+                                               MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                               MV88E61XX_SMI_PHY_COMMAND,
+                                               (1 << SMI_CMD_BUSY_OFFSET | 1 <<
+                                                SMI_CMD_MODE_OFFSET | 2 <<
+                                                SMI_CMD_OP_OFFSET | prt <<
+                                                SMI_CMD_ADDR_OFFSET | i));
+
+                       phy_busywait(eth_port_num);
+                       reg = 0x0;
+                       mv_sw_eth_phy_reg_read(eth_port_num,
+                                              MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                                              MV88E61XX_SMI_PHY_DATA, &reg);
+
+                       printf("page %d reg %02d = %04x\n", page, i, (u16) reg);
+               }
+       }
+
+       /* restore page address to zero */
+       reg = 0;
+       phy_busywait(eth_port_num);
+       mv_sw_eth_phy_reg_write(eth_port_num, MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                               MV88E61XX_SMI_PHY_DATA, reg);
+       phy_busywait(eth_port_num);
+       mv_sw_eth_phy_reg_write(eth_port_num, MV88E61XX_GLOBAL_2_REG_DEV_ADDR,
+                               MV88E61XX_SMI_PHY_COMMAND,
+                               (1 << SMI_CMD_BUSY_OFFSET | 1 <<
+                                SMI_CMD_MODE_OFFSET | 1 << SMI_CMD_OP_OFFSET |
+                                prt << SMI_CMD_ADDR_OFFSET | 22));
+
+       return 0;
+}
+
+U_BOOT_CMD(dump61xxphy, CONFIG_SYS_MAXARGS, 1, do_dump61xxphy,
+          "dump61xxphy - dump 88361xx registers\n",
+          "var [...]\n"
+          "    - run the commands in the environment variable(s) 'var'\n");
+#endif /* CONFIG_CMD_DUMP61XXPHY */
+
+#endif /* CONFIG_SWITCH_88E61XX */
-- 
1.5.3.3

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to