--- /dev/null
+/*
+ * (C) Copyright 2012
+ * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.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
+ */
+
+#include <common.h>
+#include <miiphy.h>
+#include <asm/errno.h>
+#include <mv88e6352.h>
+
+#define SMI_HDR                ((0x8 | 0x1) << 12)
+#define SMI_BUSY_MASK  (0x8000)
+#define SMIRD_OP       (0x2 << 10)
+#define SMIWR_OP       (0x1 << 10)
+#define SMI_MASK       0x1f
+#define PORT_SHIFT     5
+
+#define COMMAND_REG    0
+#define DATA_REG       1
+
+/* global registers */
+#define GLOBAL         0x1b
+
+#define GLOBAL_STATUS  0x00
+#define PPU_STATE      0x8000
+
+#define GLOBAL_CTRL    0x04
+#define SW_RESET       0x8000
+#define PPU_ENABLE     0x4000
+
+static int sw_wait_rdy(const char *devname, u8 phy_addr)
+{
+       u16 command;
+       u32 timeout = 100;
+       int ret;
+
+       /* wait till the SMI is not busy */
+       do {
+               /* read command register */
+               ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
+               if (ret < 0) {
+                       printf("%s: Error reading command register\n",
+                               __func__);
+                       return ret;
+               }
+               if (timeout-- == 0) {
+                       printf("Err..(%s) SMI busy timeout\n", __func__);
+                       return -EFAULT;
+               }
+       } while (command & SMI_BUSY_MASK);
+
+       return 0;
+}
+
+static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
+       u8 reg, u16 *data)
+{
+       int ret;
+       u16 command;
+
+       ret = sw_wait_rdy(devname, phy_addr);
+       if (ret)
+               return ret;
+
+       command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
+                       (reg & SMI_MASK);
+       debug("%s: write to command: %#x\n", __func__, command);
+       ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
+       if (ret)
+               return ret;
+
+       ret = sw_wait_rdy(devname, phy_addr);
+       if (ret)
+               return ret;
+
+       ret = miiphy_read(devname, phy_addr, DATA_REG, data);
+
+       return ret;
+}
+
+static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
+       u8 reg, u16 data)
+{
+       int ret;
+       u16 value;
+
+       ret = sw_wait_rdy(devname, phy_addr);
+       if (ret)
+               return ret;
+
+       debug("%s: write to data: %#x\n", __func__, data);
+       ret = miiphy_write(devname, phy_addr, DATA_REG, data);
+       if (ret)
+               return ret;
+
+       value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
+                       (reg & SMI_MASK);
+       debug("%s: write to command: %#x\n", __func__, value);
+       ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
+       if (ret)
+               return ret;
+
+       ret = sw_wait_rdy(devname, phy_addr);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int ppu_enable(const char *devname, u8 phy_addr)
+{
+       int i, ret = 0;
+       u16 reg;
+
+       ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
+       if (ret) {
+               printf("%s: Error reading global ctrl reg\n", __func__);
+               return ret;
+       }
+
+       reg |= PPU_ENABLE;
+
+       ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
+       if (ret) {
+               printf("%s: Error writing global ctrl reg\n", __func__);
+               return ret;
+       }
+
+       for (i = 0; i < 1000; i++) {
+               sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
+                       ®);
+               if ((reg & 0xc000) == 0xc000)
+                       return 0;
+               udelay(1000);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int ppu_disable(const char *devname, u8 phy_addr)
+{
+       int i, ret = 0;
+       u16 reg;
+
+       ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
+       if (ret) {
+               printf("%s: Error reading global ctrl reg\n", __func__);
+               return ret;
+       }
+
+       reg &= ~PPU_ENABLE;
+
+       ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
+       if (ret) {
+               printf("%s: Error writing global ctrl reg\n", __func__);
+               return ret;
+       }
+
+       for (i = 0; i < 1000; i++) {
+               sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
+                       ®);
+               if ((reg & 0xc000) != 0xc000)
+                       return 0;
+               udelay(1000);
+       }
+
+       return -ETIMEDOUT;
+}
+
+int mv88e_sw_program(const char *devname, u8 phy_addr,
+       struct mv88e_sw_reg *regs, int regs_nb)
+{
+       int i, ret = 0;
+
+       /* first we need to disable the PPU */
+       ret = ppu_disable(devname, phy_addr);
+       if (ret) {
+               printf("%s: Error disabling PPU\n", __func__);
+               return ret;
+       }
+
+       for (i = 0; i < regs_nb; i++) {
+               ret = sw_reg_write(devname, phy_addr, regs[i].port,
+                       regs[i].reg, regs[i].value);
+               if (ret) {
+                       printf("%s: Error configuring switch\n", __func__);
+                       ppu_enable(devname, phy_addr);
+                       return ret;
+               }
+       }
+
+       /* re-enable the PPU */
+       ret = ppu_enable(devname, phy_addr);
+       if (ret) {
+               printf("%s: Error enabling PPU\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+int mv88e_sw_reset(const char *devname, u8 phy_addr)
+{
+       int i, ret = 0;
+       u16 reg;
+
+       ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, ®);
+       if (ret) {
+               printf("%s: Error reading global ctrl reg\n", __func__);
+               return ret;
+       }
+
+       reg = SW_RESET | PPU_ENABLE | 0x0400;
+
+       ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
+       if (ret) {
+               printf("%s: Error writing global ctrl reg\n", __func__);
+               return ret;
+       }
+
+       for (i = 0; i < 1000; i++) {
+               sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
+                       ®);
+               if ((reg & 0xc800) != 0xc800)
+                       return 0;
+               udelay(1000);
+       }
+
+       return -ETIMEDOUT;
+}
+
+int do_mvsw_reg_read(const char *name, int argc, char * const argv[])
+{
+       u16 value = 0, phyaddr, reg, port;
+       int ret;
+
+       phyaddr = simple_strtoul(argv[1], NULL, 10);
+       port = simple_strtoul(argv[2], NULL, 10);
+       reg = simple_strtoul(argv[3], NULL, 10);
+
+       ret = sw_reg_read(name, phyaddr, port, reg, &value);
+       printf("%#x\n", value);
+
+       return ret;
+}
+
+int do_mvsw_reg_write(const char *name, int argc, char * const argv[])
+{
+       u16 value = 0, phyaddr, reg, port;
+       int ret;
+
+       phyaddr = simple_strtoul(argv[1], NULL, 10);
+       port = simple_strtoul(argv[2], NULL, 10);
+       reg = simple_strtoul(argv[3], NULL, 10);
+       value = simple_strtoul(argv[4], NULL, 16);
+
+       ret = sw_reg_write(name, phyaddr, port, reg, value);
+
+       return ret;
+}
+
+
+int do_mvsw_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int ret;
+       const char *cmd, *ethname;
+
+       if (argc < 2)
+               return cmd_usage(cmdtp);
+
+       cmd = argv[1];
+       --argc;
+       ++argv;
+
+       if (strcmp(cmd, "read") == 0) {
+               if (argc < 5)
+                       return cmd_usage(cmdtp);
+               ethname = argv[1];
+               --argc;
+               ++argv;
+               ret = do_mvsw_reg_read(ethname, argc, argv);
+       } else if (strcmp(cmd, "write") == 0) {
+               if (argc < 6)
+                       return cmd_usage(cmdtp);
+               ethname = argv[1];
+               --argc;
+               ++argv;
+               ret = do_mvsw_reg_write(ethname, argc, argv);
+       } else
+               return cmd_usage(cmdtp);
+
+       return ret;
+}
+
+U_BOOT_CMD(
+       mvsw_reg,       7,      1,      do_mvsw_reg,
+       "marvell 88e6352 switch register access",
+       "write ethname phyaddr port reg value\n"
+       "mvsw_reg read  ethname phyaddr port reg\n"
+       );
 
--- /dev/null
+/*
+ * (C) Copyright 2012
+ * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.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 __MV886352_H
+#define __MV886352_H
+
+#include <common.h>
+
+/* PHY registers */
+#define PHY(itf)       (itf)
+
+#define PHY_CTRL       0x00
+#define PHY_100_MBPS   0x2000
+#define PHY_1_GBPS     0x0040
+#define AUTONEG_EN     0x1000
+#define AUTONEG_RST    0x0200
+#define FULL_DUPLEX    0x0100
+#define PHY_PWR_DOWN   0x0800
+
+#define PHY_STATUS     0x01
+#define AN1000FIX      0x0001
+
+#define PHY_SPEC_CTRL  0x10
+#define SPEC_PWR_DOWN  0x0004
+#define AUTO_MDIX_EN   0x0060
+
+#define PHY_1000_CTRL  0x9
+
+#define NO_ADV         0x0000
+#define ADV_1000_FDPX  0x0200
+#define ADV_1000_HDPX  0x0100
+
+#define PHY_PAGE       0x16
+
+#define AN1000FIX_PAGE 0x00fc
+
+/* PORT or MAC registers */
+#define PORT(itf)      (itf+0x10)
+
+#define PORT_STATUS    0x00
+#define NO_PHY_DETECT  0x0000
+
+#define PORT_PHY       0x01
+#define RX_RGMII_TIM   0x8000
+#define TX_RGMII_TIM   0x4000
+#define FLOW_CTRL_EN   0x0080
+#define FLOW_CTRL_FOR  0x0040
+#define LINK_VAL       0x0020
+#define LINK_FOR       0x0010
+#define FULL_DPX       0x0008
+#define FULL_DPX_FOR   0x0004
+#define NO_SPEED_FOR   0x0003
+#define SPEED_1000_FOR 0x0002
+#define SPEED_100_FOR  0x0001
+#define SPEED_10_FOR   0x0000
+
+#define PORT_CTRL      0x04
+#define FORWARDING     0x0003
+#define EGRS_FLD_ALL   0x000c
+#define PORT_DIS       0x0000
+
+struct mv88e_sw_reg {
+       u8 port;
+       u8 reg;
+       u16 value;
+};
+
+int mv88e_sw_reset(const char *devname, u8 phy_addr);
+int mv88e_sw_program(const char *devname, u8 phy_addr,
+       struct mv88e_sw_reg *regs, int regs_nb);
+
+#endif