From mboxrd@z Thu Jan 1 00:00:00 1970 From: Valentin Longchamp Date: Thu, 7 Jun 2012 12:06:52 +0200 Subject: [U-Boot] [PATCH 12/20] arm/km: add support for external switch configuration In-Reply-To: <1339063620-8890-1-git-send-email-valentin.longchamp@keymile.com> References: <1339063620-8890-1-git-send-email-valentin.longchamp@keymile.com> Message-ID: <1339063620-8890-13-git-send-email-valentin.longchamp@keymile.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de This can be used if we do not want to use an EEPROM for the configuration. Signed-off-by: Valentin Longchamp --- board/keymile/common/common.h | 7 -- board/keymile/km_arm/managed_switch.c | 169 +++++++++++++++++++++++++++++++-- board/keymile/km_arm/managed_switch.h | 99 +++++++++++++++++++ 3 files changed, 258 insertions(+), 17 deletions(-) create mode 100644 board/keymile/km_arm/managed_switch.h diff --git a/board/keymile/common/common.h b/board/keymile/common/common.h index c58e565..e9abfcd 100644 --- a/board/keymile/common/common.h +++ b/board/keymile/common/common.h @@ -125,13 +125,6 @@ struct bfticu_iomap { int ethernet_present(void); int ivm_read_eeprom(void); - -int ext_switch_reg_write(const char *devname, u8 phy_addr, u8 port, - u8 reg, u16 data); -int ext_switch_reg_read(const char *devname, u8 phy_addr, u8 port, - u8 reg, u16 *data); - - int trigger_fpga_config(void); int wait_for_fpga_config(void); int fpga_reset(void); diff --git a/board/keymile/km_arm/managed_switch.c b/board/keymile/km_arm/managed_switch.c index 482c18d..3b022cd 100644 --- a/board/keymile/km_arm/managed_switch.c +++ b/board/keymile/km_arm/managed_switch.c @@ -25,15 +25,43 @@ #include #include -#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 +#include "managed_switch.h" -#define COMMAND_REG 0 -#define DATA_REG 1 +#if defined(CONFIG_KM_NUSA) +struct switch_reg sw_conf[] = { + /* port 0, PIGY4, autoneg */ + { PORT(0), PORT_PHY, NO_SPEED_FOR }, + { PORT(0), PORT_CTRL, FORWARDING | EGRS_FLD_ALL }, + { PHY(0), PHY_CTRL, PHY_100_MBPS | AUTONEG_EN | AUTONEG_RST | + FULL_DUPLEX }, + { PHY(0), PHY_SPEC_CTRL, AUTO_MDIX_EN }, + /* port 1, unused */ + { PORT(1), PORT_CTRL, PORT_DIS }, + { PHY(1), PHY_CTRL, PHY_PWR_DOWN }, + { PHY(1), PHY_SPEC_CTRL, SPEC_PWR_DOWN }, + /* port 2, unused */ + { PORT(2), PORT_CTRL, PORT_DIS }, + { PHY(2), PHY_CTRL, PHY_PWR_DOWN }, + { PHY(2), PHY_SPEC_CTRL, SPEC_PWR_DOWN }, + /* port 3, unused */ + { PORT(3), PORT_CTRL, PORT_DIS }, + { PHY(3), PHY_CTRL, PHY_PWR_DOWN }, + { PHY(3), PHY_SPEC_CTRL, SPEC_PWR_DOWN }, + /* port 4, ICNEV, SerDes, SGMII */ + { PORT(4), PORT_STATUS, NO_PHY_DETECT }, + { PORT(4), PORT_PHY, SPEED_1000_FOR }, + { PORT(4), PORT_CTRL, FORWARDING | EGRS_FLD_ALL }, + { PHY(4), PHY_CTRL, PHY_PWR_DOWN }, + { PHY(4), PHY_SPEC_CTRL, SPEC_PWR_DOWN }, + /* port 5, CPU_RGMII */ + { PORT(5), PORT_PHY, RX_RGMII_TIM | TX_RGMII_TIM | FLOW_CTRL_EN | + FLOW_CTRL_FOR | LINK_VAL | LINK_FOR | FULL_DPX | + FULL_DPX_FOR | SPEED_1000_FOR }, + { PORT(5), PORT_CTRL, FORWARDING | EGRS_FLD_ALL }, + /* port 6, unused, this port has no phy */ + { PORT(6), PORT_CTRL, PORT_DIS }, +}; +#endif static int ext_switch_wait_rdy(const char *devname, u8 phy_addr) { @@ -59,7 +87,7 @@ static int ext_switch_wait_rdy(const char *devname, u8 phy_addr) return 0; } -int ext_switch_reg_read(const char *devname, u8 phy_addr, u8 port, +static int ext_switch_reg_read(const char *devname, u8 phy_addr, u8 port, u8 reg, u16 *data) { int ret; @@ -85,7 +113,7 @@ int ext_switch_reg_read(const char *devname, u8 phy_addr, u8 port, return ret; } -int ext_switch_reg_write(const char *devname, u8 phy_addr, u8 port, +static int ext_switch_reg_write(const char *devname, u8 phy_addr, u8 port, u8 reg, u16 data) { int ret; @@ -114,6 +142,127 @@ int ext_switch_reg_write(const char *devname, u8 phy_addr, u8 port, return 0; } +static int ppu_enable(const char *devname, u8 phy_addr) +{ + int i, ret = 0; + u16 reg; + + ret = ext_switch_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 = ext_switch_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++) { + ext_switch_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 = ext_switch_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 = ext_switch_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++) { + ext_switch_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS, + ®); + if ((reg & 0xc000) != 0xc000) + return 0; + udelay(1000); + } + + return -ETIMEDOUT; +} + +int ext_switch_program(const char *devname, u8 phy_addr) +{ + 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 < ARRAY_SIZE(sw_conf); i++) { + ret = ext_switch_reg_write(devname, phy_addr, sw_conf[i].port, + sw_conf[i].reg, sw_conf[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 ext_switch_reset(const char *devname, u8 phy_addr) +{ + int i, ret = 0; + u16 reg; + + ret = ext_switch_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 = ext_switch_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++) { + ext_switch_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS, + ®); + if ((reg & 0xc800) != 0xc800) + return 0; + udelay(1000); + } + + return -ETIMEDOUT; +} + int do_sw_reg_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *name = "egiga0"; diff --git a/board/keymile/km_arm/managed_switch.h b/board/keymile/km_arm/managed_switch.h new file mode 100644 index 0000000..c0dcf82 --- /dev/null +++ b/board/keymile/km_arm/managed_switch.h @@ -0,0 +1,99 @@ +/* + * (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 __MANAGED_SWITCH_H +#define __MANAGED_SWITCH_H + +#include + +#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 + +/* PHY registers */ +#define PHY(itf) (itf) + +#define PHY_CTRL 0x00 +#define PHY_100_MBPS 0x2000 +#define AUTONEG_EN 0x1000 +#define AUTONEG_RST 0x0200 +#define FULL_DUPLEX 0x0100 +#define PHY_PWR_DOWN 0x0800 + +#define PHY_STATUS 0x01 + +#define PHY_SPEC_CTRL 0x10 +#define SPEC_PWR_DOWN 0x0004 +#define AUTO_MDIX_EN 0x0060 + +/* 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 switch_reg { + u8 port; + u8 reg; + u16 value; +}; + +int ext_switch_reset(const char *devname, u8 phy_addr); +int ext_switch_program(const char *devname, u8 phy_addr); + +#endif -- 1.7.1