diff options
Diffstat (limited to 'package/boot/uboot-ar71xx/files/drivers/net/phy')
7 files changed, 2054 insertions, 0 deletions
diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/entries b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/entries new file mode 100644 index 0000000..ad8ef18 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +36060 +svn://svn.openwrt.org/openwrt/trunk/package/boot/uboot-ar71xx/files/drivers/net/phy +svn://svn.openwrt.org/openwrt + + + +2012-10-16T13:44:25.630275Z +33781 +blogic + + + + + + + + + + + + + + +3c298f89-4303-0410-b956-a3cf2f4a3e73 + +rtl8366_mii.c +file + + + + +2013-03-17T12:13:21.000000Z +2075819b75c9da42261c89c49b53bf2d +2012-10-16T13:44:25.630275Z +33781 +blogic +has-props + + + + + + + + + + + + + + + + + + + + +18599 + +rtl8366.h +file + + + + +2013-03-17T12:13:21.000000Z +6bca21a0bce104b8b2de10207b04b584 +2012-10-16T13:44:25.630275Z +33781 +blogic +has-props + + + + + + + + + + + + + + + + + + + + +6036 + diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/prop-base/rtl8366.h.svn-base b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/prop-base/rtl8366.h.svn-base new file mode 100644 index 0000000..bdbd305 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/prop-base/rtl8366.h.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:eol-style +V 6 +native +END diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/prop-base/rtl8366_mii.c.svn-base b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/prop-base/rtl8366_mii.c.svn-base new file mode 100644 index 0000000..bdbd305 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/prop-base/rtl8366_mii.c.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:eol-style +V 6 +native +END diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/text-base/rtl8366.h.svn-base b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/text-base/rtl8366.h.svn-base new file mode 100644 index 0000000..f0567dd --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/text-base/rtl8366.h.svn-base @@ -0,0 +1,188 @@ +/* + * (C) Copyright 2010 + * Michael Kurz <michi.kurz@googlemail.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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef RTL8366_MII_H +#define RTL8366_MII_H + +#define MII_CONTROL_REG 0 +#define MII_STATUS_REG 1 +#define MII_PHY_ID0 2 +#define MII_PHY_ID1 3 +#define MII_LOCAL_CAP 4 +#define MII_REMOTE_CAP 5 +#define MII_EXT_AUTONEG 6 +#define MII_LOCAL_NEXT_PAGE 7 +#define MII_REMOTE_NEXT_PAGE 8 +#define MII_GIGA_CONTROL 9 +#define MII_GIGA_STATUS 10 +#define MII_EXT_STATUS_REG 15 + +/* Control register */ +#define MII_CONTROL_1000MBPS 6 +#define MII_CONTROL_COLL_TEST 7 +#define MII_CONTROL_FULLDUPLEX 8 +#define MII_CONTROL_RENEG 9 +#define MII_CONTROL_ISOLATE 10 +#define MII_CONTROL_POWERDOWN 11 +#define MII_CONTROL_AUTONEG 12 +#define MII_CONTROL_100MBPS 13 +#define MII_CONTROL_LOOPBACK 14 +#define MII_CONTROL_RESET 15 + +/* Status/Extended status register */ +/* Basic status */ +#define MII_STATUS_CAPABILITY 0 +#define MII_STATUS_JABBER 1 +#define MII_STATUS_LINK_UP 2 +#define MII_STATUS_AUTONEG_ABLE 3 +#define MII_STATUS_REMOTE_FAULT 4 +#define MII_STATUS_AUTONEG_DONE 5 +#define MII_STATUS_NO_PREAMBLE 6 +#define MII_STATUS_RESERVED 7 +#define MII_STATUS_EXTENDED 8 +#define MII_STATUS_100_T2_HALF 9 +#define MII_STATUS_100_T2_FULL 10 +#define MII_STATUS_10_TX_HALF 11 +#define MII_STATUS_10_TX_FULL 12 +#define MII_STATUS_100_TX_HALF 13 +#define MII_STATUS_100_TX_FULL 14 +#define MII_STATUS_100_T4 15 + +#define MII_GIGA_CONTROL_HALF 8 +#define MII_GIGA_CONTROL_FULL 9 +#define MII_GIGA_STATUS_HALF 10 +#define MII_GIGA_STATUS_FULL 11 + +/* Extended status */ +#define MII_STATUS_1000_T_HALF 12 +#define MII_STATUS_1000_T_FULL 13 +#define MII_STATUS_1000_X_HALF 14 +#define MII_STATUS_1000_X_FULL 15 + +/* Local/Remmote capability register */ +#define MII_CAP_10BASE_TX 5 +#define MII_CAP_10BASE_TX_FULL 6 +#define MII_CAP_100BASE_TX 7 +#define MII_CAP_100BASE_TX_FULL 8 +#define MII_CAP_100BASE_T4 9 +#define MII_CAP_SYMM_PAUSE 10 +#define MII_CAP_ASYMM_PAUSE 11 +#define MII_CAP_RESERVED 12 +#define MII_CAP_REMOTE_FAULT 13 +#define MII_CAP_ACKNOWLEDGE 14 +#define MII_CAP_NEXT_PAGE 15 +#define MII_CAP_IEEE_802_3 0x0001 + +#define MII_LINK_MODE_MASK 0x1f + +#define REALTEK_RTL8366_CHIP_ID0 0x001C +#define REALTEK_RTL8366_CHIP_ID1 0xC940 +#define REALTEK_RTL8366_CHIP_ID1_MP 0xC960 + +#define REALTEK_MIN_PORT_ID 0 +#define REALTEK_MAX_PORT_ID 5 +#define REALTEK_MIN_PHY_ID REALTEK_MIN_PORT_ID +#define REALTEK_MAX_PHY_ID 4 +#define REALTEK_CPU_PORT_ID REALTEK_MAX_PORT_ID +#define REALTEK_PHY_PORT_MASK ((1<<(REALTEK_MAX_PHY_ID+1)) - (1<<REALTEK_MIN_PHY_ID)) +#define REALTEK_CPU_PORT_MASK (1<<REALTEK_CPU_PORT_ID) +#define REALTEK_ALL_PORT_MASK (REALTEK_PHY_PORT_MASK | REALTEK_CPU_PORT_MASK) + +/* port ability */ +#define RTL8366S_PORT_ABILITY_BASE 0x0011 + +/* port vlan control register */ +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 + +/* port linking status */ +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 +#define RTL8366S_PORT_STATUS_SPEED_BIT 0 +#define RTL8366S_PORT_STATUS_SPEED_MSK 0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_BIT 2 +#define RTL8366S_PORT_STATUS_DUPLEX_MSK 0x0004 +#define RTL8366S_PORT_STATUS_LINK_BIT 4 +#define RTL8366S_PORT_STATUS_LINK_MSK 0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_BIT 5 +#define RTL8366S_PORT_STATUS_TXPAUSE_MSK 0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_BIT 6 +#define RTL8366S_PORT_STATUS_RXPAUSE_MSK 0x0040 +#define RTL8366S_PORT_STATUS_AN_BIT 7 +#define RTL8366S_PORT_STATUS_AN_MSK 0x0080 + +/* internal control */ +#define RTL8366S_RESET_CONTROL_REG 0x0100 +#define RTL8366S_RESET_QUEUE_BIT 2 + +#define RTL8366S_CHIP_ID_REG 0x0105 + +/* MAC control */ +#define RTL8366S_MAC_FORCE_CTRL0_REG 0x0F04 +#define RTL8366S_MAC_FORCE_CTRL1_REG 0x0F05 + + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 + +#define RTL8366S_PHY_CTRL_READ 1 +#define RTL8366S_PHY_CTRL_WRITE 0 + +#define RTL8366S_PHY_REG_MASK 0x1F +#define RTL8366S_PHY_PAGE_OFFSET 5 +#define RTL8366S_PHY_PAGE_MASK (0x7<<5) +#define RTL8366S_PHY_NO_OFFSET 9 +#define RTL8366S_PHY_NO_MASK (0x1F<<9) + +#define RTL8366S_PHY_NO_MAX 4 +#define RTL8366S_PHY_PAGE_MAX 7 +#define RTL8366S_PHY_ADDR_MAX 31 + +/* cpu port control reg */ +#define RTL8366S_CPU_CTRL_REG 0x004F +#define RTL8366S_CPU_DRP_BIT 14 +#define RTL8366S_CPU_DRP_MSK 0x4000 +#define RTL8366S_CPU_INSTAG_BIT 15 +#define RTL8366S_CPU_INSTAG_MSK 0x8000 + +/* LED registers*/ +#define RTL8366S_LED_BLINK_REG 0x420 +#define RTL8366S_LED_BLINKRATE_BIT 0 +#define RTL8366S_LED_BLINKRATE_MSK 0x0007 +#define RTL8366S_LED_INDICATED_CONF_REG 0x421 +#define RTL8366S_LED_0_1_FORCE_REG 0x422 +#define RTL8366S_LED_2_3_FORCE_REG 0x423 +#define RTL8366S_LEDCONF_LEDFORCE 0x1F +#define RTL8366S_LED_GROUP_MAX 4 + +#define RTL8366S_GREEN_FEATURE_REG 0x000A +#define RTL8366S_GREEN_FEATURE_TX_BIT 3 +#define RTL8366S_GREEN_FEATURE_TX_MSK 0x0008 +#define RTL8366S_GREEN_FEATURE_RX_BIT 4 +#define RTL8366S_GREEN_FEATURE_RX_MSK 0x0010 + +#define RTL8366S_MODEL_ID_REG 0x5C +#define RTL8366S_REV_ID_REG 0x5D +#define RTL8366S_MODEL_8366SR 0x6027 +#define RTL8366S_MODEL_8366RB 0x5937 + +#endif diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/text-base/rtl8366_mii.c.svn-base b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/text-base/rtl8366_mii.c.svn-base new file mode 100644 index 0000000..e3c5316 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/.svn/text-base/rtl8366_mii.c.svn-base @@ -0,0 +1,786 @@ +/* + * (C) Copyright 2010 + * Michael Kurz <michi.kurz@googlemail.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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <net.h> +#include <netdev.h> +#include <miiphy.h> +#include MII_GPIOINCLUDE + +#include "rtl8366.h" + +#ifdef DEBUG_RTL8366 + #define DBG(fmt,args...) printf (fmt ,##args) +#else + #define DBG(fmt,args...) +#endif + + +//------------------------------------------------------------------- +// Soft SMI functions +//------------------------------------------------------------------- + +#define DELAY 2 + +static void smi_init(void) +{ + MII_SDAINPUT; + MII_SCKINPUT; + + MII_SETSDA(1); + MII_SETSCK(1); + + udelay(20); +} + +static void smi_start(void) +{ +/* + * rtl8366 chip needs a extra clock with + * SDA high before start condition + */ + + /* set gpio pins output */ + MII_SDAOUTPUT; + MII_SCKOUTPUT; + udelay(DELAY); + + /* set initial state: SCK:0, SDA:1 */ + MII_SETSCK(0); + MII_SETSDA(1); + udelay(DELAY); + + /* toggle clock */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + + /* start condition */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSDA(0); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + MII_SETSDA(1); +} + +static void smi_stop(void) +{ +/* + * rtl8366 chip needs a extra clock with + * SDA high after stop condition + */ + + /* stop condition */ + udelay(DELAY); + MII_SETSDA(0); + MII_SETSCK(1); + udelay(DELAY); + MII_SETSDA(1); + udelay(DELAY); + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + + /* toggle clock */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + MII_SETSCK(1); + + /* set gpio pins input */ + MII_SDAINPUT; + MII_SCKINPUT; +} + +static void smi_writeBits(uint32_t data, uint8_t length) +{ + uint8_t test; + + for( ; length > 0; length--) { + udelay(DELAY); + + /* output data */ + test = (((data & (1 << (length - 1))) != 0) ? 1 : 0); + MII_SETSDA(test); + udelay(DELAY); + + /* toogle clock */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + } +} + +static uint32_t smi_readBits(uint8_t length) +{ + uint32_t ret; + + MII_SDAINPUT; + + for(ret = 0 ; length > 0; length--) { + udelay(DELAY); + + ret <<= 1; + + /* toogle clock */ + MII_SETSCK(1); + udelay(DELAY); + ret |= MII_GETSDA; + MII_SETSCK(0); + } + + MII_SDAOUTPUT; + + return ret; +} + +static int smi_waitAck(void) +{ + uint32_t retry = 0; + + while (smi_readBits(1)) { + if (retry++ == 5) + return -1; + } + + return 0; + +} + +static int smi_read(uint32_t reg, uint32_t *data) +{ + uint32_t rawData; + + /* send start condition */ + smi_start(); + /* send CTRL1 code: 0b1010*/ + smi_writeBits(0x0a, 4); + /* send CTRL2 code: 0b100 */ + smi_writeBits(0x04, 3); + /* send READ command */ + smi_writeBits(0x01, 1); + + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send address low */ + smi_writeBits(reg & 0xFF, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + /* send address high */ + smi_writeBits((reg & 0xFF00) >> 8, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* read data low */ + rawData = (smi_readBits(8) & 0xFF); + /* send ACK */ + smi_writeBits(0, 1); + /* read data high */ + rawData |= (smi_readBits(8) & 0xFF) << 8; + /* send NACK */ + smi_writeBits(1, 1); + + /* send stop condition */ + smi_stop(); + + if (data) + *data = rawData; + + return 0; +} + +static int smi_write(uint32_t reg, uint32_t data) +{ + /* send start condition */ + smi_start(); + /* send CTRL1 code: 0b1010*/ + smi_writeBits(0x0a, 4); + /* send CTRL2 code: 0b100 */ + smi_writeBits(0x04, 3); + /* send WRITE command */ + smi_writeBits(0x00, 1); + + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send address low */ + smi_writeBits(reg & 0xFF, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + /* send address high */ + smi_writeBits((reg & 0xFF00) >> 8, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send data low */ + smi_writeBits(data & 0xFF, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + /* send data high */ + smi_writeBits((data & 0xFF00) >> 8, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send stop condition */ + smi_stop(); + + return 0; +} + + +//------------------------------------------------------------------- +// Switch register read / write functions +//------------------------------------------------------------------- +static int rtl8366_readRegister(uint32_t reg, uint16_t *data) +{ + uint32_t regData; + + DBG("rtl8366: read register=%#04x, data=", reg); + + if (smi_read(reg, ®Data)) { + printf("\nrtl8366 smi read failed!\n"); + return -1; + } + + if (data) + *data = regData; + + DBG("%#04x\n", regData); + + return 0; +} + +static int rtl8366_writeRegister(uint32_t reg, uint16_t data) +{ + DBG("rtl8366: write register=%#04x, data=%#04x\n", reg, data); + + if (smi_write(reg, data)) { + printf("rtl8366 smi write failed!\n"); + return -1; + } + + return 0; +} + +static int rtl8366_setRegisterBit(uint32_t reg, uint32_t bitNum, uint32_t value) +{ + uint16_t regData; + + if (bitNum >= 16) + return -1; + + if (rtl8366_readRegister(reg, ®Data)) + return -1; + + if (value) + regData |= (1 << bitNum); + else + regData &= ~(1 << bitNum); + + if (rtl8366_writeRegister(reg, regData)) + return -1; + + return 0; +} + +//------------------------------------------------------------------- +// MII PHY read / write functions +//------------------------------------------------------------------- +static int rtl8366_getPhyReg(uint32_t phyNum, uint32_t reg, uint16_t *data) +{ + uint16_t phyAddr, regData; + + if (phyNum > RTL8366S_PHY_NO_MAX) { + printf("rtl8366s: invalid phy number!\n"); + return -1; + } + + if (phyNum > RTL8366S_PHY_ADDR_MAX) { + printf("rtl8366s: invalid phy register number!\n"); + return -1; + } + + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_READ)) + return -1; + + phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) + | (reg & RTL8366S_PHY_REG_MASK); + if (rtl8366_writeRegister(phyAddr, 0)) + return -1; + + if (rtl8366_readRegister(RTL8366S_PHY_ACCESS_DATA_REG, ®Data)) + return -1; + + if (data) + *data = regData; + + return 0; +} + +static int rtl8366_setPhyReg(uint32_t phyNum, uint32_t reg, uint16_t data) +{ + uint16_t phyAddr; + + if (phyNum > RTL8366S_PHY_NO_MAX) { + printf("rtl8366s: invalid phy number!\n"); + return -1; + } + + if (phyNum > RTL8366S_PHY_ADDR_MAX) { + printf("rtl8366s: invalid phy register number!\n"); + return -1; + } + + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE)) + return -1; + + phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) + | (reg & RTL8366S_PHY_REG_MASK); + if (rtl8366_writeRegister(phyAddr, data)) + return -1; + + return 0; +} + +static int rtl8366_miiread(char *devname, uchar phy_adr, uchar reg, ushort *data) +{ + uint16_t regData; + + DBG("rtl8366_miiread: devname=%s, addr=%#02x, reg=%#02x\n", + devname, phy_adr, reg); + + if (strcmp(devname, RTL8366_DEVNAME) != 0) + return -1; + + if (rtl8366_getPhyReg(phy_adr, reg, ®Data)) { + printf("rtl8366_miiread: write failed!\n"); + return -1; + } + + if (data) + *data = regData; + + return 0; +} + +static int rtl8366_miiwrite(char *devname, uchar phy_adr, uchar reg, ushort data) +{ + DBG("rtl8366_miiwrite: devname=%s, addr=%#02x, reg=%#02x, data=%#04x\n", + devname, phy_adr, reg, data); + + if (strcmp(devname, RTL8366_DEVNAME) != 0) + return -1; + + if (rtl8366_setPhyReg(phy_adr, reg, data)) { + printf("rtl8366_miiwrite: write failed!\n"); + return -1; + } + + return 0; +} + +int rtl8366_mii_register(bd_t *bis) +{ + miiphy_register(strdup(RTL8366_DEVNAME), rtl8366_miiread, + rtl8366_miiwrite); + + return 0; +} + + +//------------------------------------------------------------------- +// Switch management functions +//------------------------------------------------------------------- + +int rtl8366s_setGreenFeature(uint32_t tx, uint32_t rx) +{ + if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, + RTL8366S_GREEN_FEATURE_TX_BIT, tx)) + return -1; + + if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, + RTL8366S_GREEN_FEATURE_RX_BIT, rx)) + return -1; + + return 0; +} + +int rtl8366s_setPowerSaving(uint32_t phyNum, uint32_t enabled) +{ + uint16_t regData; + + if (phyNum > RTL8366S_PHY_NO_MAX) + return -1; + + if (rtl8366_getPhyReg(phyNum, 12, ®Data)) + return -1; + + if (enabled) + regData |= (1 << 12); + else + regData &= ~(1 << 12); + + if (rtl8366_setPhyReg(phyNum, 12, regData)) + return -1; + + return 0; +} + +int rtl8366s_setGreenEthernet(uint32_t greenFeature, uint32_t powerSaving) +{ + uint32_t phyNum, i; + uint16_t regData; + + const uint16_t greenSettings[][2] = + { + {0xBE5B,0x3500}, + {0xBE5C,0xB975}, + {0xBE5D,0xB9B9}, + {0xBE77,0xA500}, + {0xBE78,0x5A78}, + {0xBE79,0x6478} + }; + + if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) + return -1; + + switch (regData) + { + case 0x0000: + for (i = 0; i < 6; i++) { + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) + return -1; + if (rtl8366_writeRegister(greenSettings[i][0], greenSettings[i][1])) + return -1; + } + break; + + case RTL8366S_MODEL_8366SR: + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) + return -1; + if (rtl8366_writeRegister(greenSettings[0][0], greenSettings[0][1])) + return -1; + break; + + default: + printf("rtl8366s_initChip: unsupported chip found!\n"); + return -1; + } + + if (rtl8366s_setGreenFeature(greenFeature, powerSaving)) + return -1; + + for (phyNum = 0; phyNum <= RTL8366S_PHY_NO_MAX; phyNum++) { + if (rtl8366s_setPowerSaving(phyNum, powerSaving)) + return -1; + } + + return 0; +} + +int rtl8366s_setCPUPortMask(uint8_t port, uint32_t enabled) +{ + if(port >= 6){ + printf("rtl8366s_setCPUPortMask: invalid port number\n"); + return -1; + } + + return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, port, enabled); +} + +int rtl8366s_setCPUDisableInsTag(uint32_t enable) +{ + return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, + RTL8366S_CPU_INSTAG_BIT, enable); +} + +int rtl8366s_setCPUDropUnda(uint32_t enable) +{ + return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, + RTL8366S_CPU_DRP_BIT, enable); +} + +int rtl8366s_setCPUPort(uint8_t port, uint32_t noTag, uint32_t dropUnda) +{ + uint32_t i; + + if(port >= 6){ + printf("rtl8366s_setCPUPort: invalid port number\n"); + return -1; + } + + /* reset register */ + for(i = 0; i < 6; i++) + { + if(rtl8366s_setCPUPortMask(i, 0)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); + return -1; + } + } + + if(rtl8366s_setCPUPortMask(port, 1)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); + return -1; + } + + if(rtl8366s_setCPUDisableInsTag(noTag)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUDisableInsTag fail\n"); + return -1; + } + + if(rtl8366s_setCPUDropUnda(dropUnda)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUDropUnda fail\n"); + return -1; + } + + return 0; +} + +int rtl8366s_setLedConfig(uint32_t ledNum, uint8_t config) +{ + uint16_t regData; + + if(ledNum >= RTL8366S_LED_GROUP_MAX) { + DBG("rtl8366s_setLedConfig: invalid led group\n"); + return -1; + } + + if(config > RTL8366S_LEDCONF_LEDFORCE) { + DBG("rtl8366s_setLedConfig: invalid led config\n"); + return -1; + } + + if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { + printf("rtl8366s_setLedConfig: failed to get led register!\n"); + return -1; + } + + regData &= ~(0xF << (ledNum * 4)); + regData |= config << (ledNum * 4); + + if (rtl8366_writeRegister(RTL8366S_LED_INDICATED_CONF_REG, regData)) { + printf("rtl8366s_setLedConfig: failed to set led register!\n"); + return -1; + } + + return 0; +} + +int rtl8366s_getLedConfig(uint32_t ledNum, uint8_t *config) +{ + uint16_t regData; + + if(ledNum >= RTL8366S_LED_GROUP_MAX) { + DBG("rtl8366s_getLedConfig: invalid led group\n"); + return -1; + } + + if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { + printf("rtl8366s_getLedConfig: failed to get led register!\n"); + return -1; + } + + if (config) + *config = (regData >> (ledNum * 4)) & 0xF; + + return 0; +} + +int rtl8366s_setLedForceValue(uint32_t group0, uint32_t group1, + uint32_t group2, uint32_t group3) +{ + uint16_t regData; + + regData = (group0 & 0x3F) | ((group1 & 0x3F) << 6); + if (rtl8366_writeRegister(RTL8366S_LED_0_1_FORCE_REG, regData)) { + printf("rtl8366s_setLedForceValue: failed to set led register!\n"); + return -1; + } + + regData = (group2 & 0x3F) | ((group3 & 0x3F) << 6); + if (rtl8366_writeRegister(RTL8366S_LED_2_3_FORCE_REG, regData)) { + printf("rtl8366s_setLedForceValue: failed to set led register!\n"); + return -1; + } + + return 0; +} + +int rtl8366s_initChip(void) +{ + uint32_t ledGroup, i = 0; + uint16_t regData; + uint8_t ledData[RTL8366S_LED_GROUP_MAX]; + const uint16_t (*chipData)[2]; + + const uint16_t chipB[][2] = + { + {0x0000, 0x0038},{0x8100, 0x1B37},{0xBE2E, 0x7B9F},{0xBE2B, 0xA4C8}, + {0xBE74, 0xAD14},{0xBE2C, 0xDC00},{0xBE69, 0xD20F},{0xBE3B, 0xB414}, + {0xBE24, 0x0000},{0xBE23, 0x00A1},{0xBE22, 0x0008},{0xBE21, 0x0120}, + {0xBE20, 0x1000},{0xBE24, 0x0800},{0xBE24, 0x0000},{0xBE24, 0xF000}, + {0xBE23, 0xDF01},{0xBE22, 0xDF20},{0xBE21, 0x101A},{0xBE20, 0xA0FF}, + {0xBE24, 0xF800},{0xBE24, 0xF000},{0x0242, 0x02BF},{0x0245, 0x02BF}, + {0x0248, 0x02BF},{0x024B, 0x02BF},{0x024E, 0x02BF},{0x0251, 0x02BF}, + {0x0230, 0x0A32},{0x0233, 0x0A32},{0x0236, 0x0A32},{0x0239, 0x0A32}, + {0x023C, 0x0A32},{0x023F, 0x0A32},{0x0254, 0x0A3F},{0x0255, 0x0064}, + {0x0256, 0x0A3F},{0x0257, 0x0064},{0x0258, 0x0A3F},{0x0259, 0x0064}, + {0x025A, 0x0A3F},{0x025B, 0x0064},{0x025C, 0x0A3F},{0x025D, 0x0064}, + {0x025E, 0x0A3F},{0x025F, 0x0064},{0x0260, 0x0178},{0x0261, 0x01F4}, + {0x0262, 0x0320},{0x0263, 0x0014},{0x021D, 0x9249},{0x021E, 0x0000}, + {0x0100, 0x0004},{0xBE4A, 0xA0B4},{0xBE40, 0x9C00},{0xBE41, 0x501D}, + {0xBE48, 0x3602},{0xBE47, 0x8051},{0xBE4C, 0x6465},{0x8000, 0x1F00}, + {0x8001, 0x000C},{0x8008, 0x0000},{0x8007, 0x0000},{0x800C, 0x00A5}, + {0x8101, 0x02BC},{0xBE53, 0x0005},{0x8E45, 0xAFE8},{0x8013, 0x0005}, + {0xBE4B, 0x6700},{0x800B, 0x7000},{0xBE09, 0x0E00}, + {0xFFFF, 0xABCD} + }; + + const uint16_t chipDefault[][2] = + { + {0x0242, 0x02BF},{0x0245, 0x02BF},{0x0248, 0x02BF},{0x024B, 0x02BF}, + {0x024E, 0x02BF},{0x0251, 0x02BF}, + {0x0254, 0x0A3F},{0x0256, 0x0A3F},{0x0258, 0x0A3F},{0x025A, 0x0A3F}, + {0x025C, 0x0A3F},{0x025E, 0x0A3F}, + {0x0263, 0x007C},{0x0100, 0x0004}, + {0xBE5B, 0x3500},{0x800E, 0x200F},{0xBE1D, 0x0F00},{0x8001, 0x5011}, + {0x800A, 0xA2F4},{0x800B, 0x17A3},{0xBE4B, 0x17A3},{0xBE41, 0x5011}, + {0xBE17, 0x2100},{0x8000, 0x8304},{0xBE40, 0x8304},{0xBE4A, 0xA2F4}, + {0x800C, 0xA8D5},{0x8014, 0x5500},{0x8015, 0x0004},{0xBE4C, 0xA8D5}, + {0xBE59, 0x0008},{0xBE09, 0x0E00},{0xBE36, 0x1036},{0xBE37, 0x1036}, + {0x800D, 0x00FF},{0xBE4D, 0x00FF}, + {0xFFFF, 0xABCD} + }; + + DBG("rtl8366s_initChip\n"); + + /* save current led config and set to led force */ + for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { + if (rtl8366s_getLedConfig(ledGroup, &ledData[ledGroup])) + return -1; + + if (rtl8366s_setLedConfig(ledGroup, RTL8366S_LEDCONF_LEDFORCE)) + return -1; + } + + if (rtl8366s_setLedForceValue(0,0,0,0)) + return -1; + + if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) + return -1; + + switch (regData) + { + case 0x0000: + chipData = chipB; + break; + + case RTL8366S_MODEL_8366SR: + chipData = chipDefault; + break; + + default: + printf("rtl8366s_initChip: unsupported chip found!\n"); + return -1; + } + + DBG("rtl8366s_initChip: found %x chip\n", regData); + + while ((chipData[i][0] != 0xFFFF) && (chipData[i][1] != 0xABCD)) { + + /* phy settings*/ + if ((chipData[i][0] & 0xBE00) == 0xBE00) { + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE)) + return -1; + } + + if (rtl8366_writeRegister(chipData[i][0], chipData[i][1])) + return -1; + + i++; + } + + /* chip needs some time */ + udelay(100 * 1000); + + /* restore led config */ + for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { + if (rtl8366s_setLedConfig(ledGroup, ledData[ledGroup])) + return -1; + } + + return 0; +} + +int rtl8366s_initialize(void) +{ + uint16_t regData; + + DBG("rtl8366s_initialize: start setup\n"); + + smi_init(); + + rtl8366_readRegister(RTL8366S_CHIP_ID_REG, ®Data); + DBG("Realtek 8366SR switch ID %#04x\n", regData); + + if (regData != 0x8366) { + printf("rtl8366s_initialize: found unsupported switch\n"); + return -1; + } + + if (rtl8366s_initChip()) { + printf("rtl8366s_initialize: init chip failed\n"); + return -1; + } + + if (rtl8366s_setGreenEthernet(1, 1)) { + printf("rtl8366s_initialize: set green ethernet failed\n"); + return -1; + } + + /* Set port 5 noTag and don't dropUnda */ + if (rtl8366s_setCPUPort(5, 1, 0)) { + printf("rtl8366s_initialize: set CPU port failed\n"); + return -1; + } + + return 0; +} diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h new file mode 100644 index 0000000..f0567dd --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h @@ -0,0 +1,188 @@ +/* + * (C) Copyright 2010 + * Michael Kurz <michi.kurz@googlemail.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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef RTL8366_MII_H +#define RTL8366_MII_H + +#define MII_CONTROL_REG 0 +#define MII_STATUS_REG 1 +#define MII_PHY_ID0 2 +#define MII_PHY_ID1 3 +#define MII_LOCAL_CAP 4 +#define MII_REMOTE_CAP 5 +#define MII_EXT_AUTONEG 6 +#define MII_LOCAL_NEXT_PAGE 7 +#define MII_REMOTE_NEXT_PAGE 8 +#define MII_GIGA_CONTROL 9 +#define MII_GIGA_STATUS 10 +#define MII_EXT_STATUS_REG 15 + +/* Control register */ +#define MII_CONTROL_1000MBPS 6 +#define MII_CONTROL_COLL_TEST 7 +#define MII_CONTROL_FULLDUPLEX 8 +#define MII_CONTROL_RENEG 9 +#define MII_CONTROL_ISOLATE 10 +#define MII_CONTROL_POWERDOWN 11 +#define MII_CONTROL_AUTONEG 12 +#define MII_CONTROL_100MBPS 13 +#define MII_CONTROL_LOOPBACK 14 +#define MII_CONTROL_RESET 15 + +/* Status/Extended status register */ +/* Basic status */ +#define MII_STATUS_CAPABILITY 0 +#define MII_STATUS_JABBER 1 +#define MII_STATUS_LINK_UP 2 +#define MII_STATUS_AUTONEG_ABLE 3 +#define MII_STATUS_REMOTE_FAULT 4 +#define MII_STATUS_AUTONEG_DONE 5 +#define MII_STATUS_NO_PREAMBLE 6 +#define MII_STATUS_RESERVED 7 +#define MII_STATUS_EXTENDED 8 +#define MII_STATUS_100_T2_HALF 9 +#define MII_STATUS_100_T2_FULL 10 +#define MII_STATUS_10_TX_HALF 11 +#define MII_STATUS_10_TX_FULL 12 +#define MII_STATUS_100_TX_HALF 13 +#define MII_STATUS_100_TX_FULL 14 +#define MII_STATUS_100_T4 15 + +#define MII_GIGA_CONTROL_HALF 8 +#define MII_GIGA_CONTROL_FULL 9 +#define MII_GIGA_STATUS_HALF 10 +#define MII_GIGA_STATUS_FULL 11 + +/* Extended status */ +#define MII_STATUS_1000_T_HALF 12 +#define MII_STATUS_1000_T_FULL 13 +#define MII_STATUS_1000_X_HALF 14 +#define MII_STATUS_1000_X_FULL 15 + +/* Local/Remmote capability register */ +#define MII_CAP_10BASE_TX 5 +#define MII_CAP_10BASE_TX_FULL 6 +#define MII_CAP_100BASE_TX 7 +#define MII_CAP_100BASE_TX_FULL 8 +#define MII_CAP_100BASE_T4 9 +#define MII_CAP_SYMM_PAUSE 10 +#define MII_CAP_ASYMM_PAUSE 11 +#define MII_CAP_RESERVED 12 +#define MII_CAP_REMOTE_FAULT 13 +#define MII_CAP_ACKNOWLEDGE 14 +#define MII_CAP_NEXT_PAGE 15 +#define MII_CAP_IEEE_802_3 0x0001 + +#define MII_LINK_MODE_MASK 0x1f + +#define REALTEK_RTL8366_CHIP_ID0 0x001C +#define REALTEK_RTL8366_CHIP_ID1 0xC940 +#define REALTEK_RTL8366_CHIP_ID1_MP 0xC960 + +#define REALTEK_MIN_PORT_ID 0 +#define REALTEK_MAX_PORT_ID 5 +#define REALTEK_MIN_PHY_ID REALTEK_MIN_PORT_ID +#define REALTEK_MAX_PHY_ID 4 +#define REALTEK_CPU_PORT_ID REALTEK_MAX_PORT_ID +#define REALTEK_PHY_PORT_MASK ((1<<(REALTEK_MAX_PHY_ID+1)) - (1<<REALTEK_MIN_PHY_ID)) +#define REALTEK_CPU_PORT_MASK (1<<REALTEK_CPU_PORT_ID) +#define REALTEK_ALL_PORT_MASK (REALTEK_PHY_PORT_MASK | REALTEK_CPU_PORT_MASK) + +/* port ability */ +#define RTL8366S_PORT_ABILITY_BASE 0x0011 + +/* port vlan control register */ +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 + +/* port linking status */ +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 +#define RTL8366S_PORT_STATUS_SPEED_BIT 0 +#define RTL8366S_PORT_STATUS_SPEED_MSK 0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_BIT 2 +#define RTL8366S_PORT_STATUS_DUPLEX_MSK 0x0004 +#define RTL8366S_PORT_STATUS_LINK_BIT 4 +#define RTL8366S_PORT_STATUS_LINK_MSK 0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_BIT 5 +#define RTL8366S_PORT_STATUS_TXPAUSE_MSK 0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_BIT 6 +#define RTL8366S_PORT_STATUS_RXPAUSE_MSK 0x0040 +#define RTL8366S_PORT_STATUS_AN_BIT 7 +#define RTL8366S_PORT_STATUS_AN_MSK 0x0080 + +/* internal control */ +#define RTL8366S_RESET_CONTROL_REG 0x0100 +#define RTL8366S_RESET_QUEUE_BIT 2 + +#define RTL8366S_CHIP_ID_REG 0x0105 + +/* MAC control */ +#define RTL8366S_MAC_FORCE_CTRL0_REG 0x0F04 +#define RTL8366S_MAC_FORCE_CTRL1_REG 0x0F05 + + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 + +#define RTL8366S_PHY_CTRL_READ 1 +#define RTL8366S_PHY_CTRL_WRITE 0 + +#define RTL8366S_PHY_REG_MASK 0x1F +#define RTL8366S_PHY_PAGE_OFFSET 5 +#define RTL8366S_PHY_PAGE_MASK (0x7<<5) +#define RTL8366S_PHY_NO_OFFSET 9 +#define RTL8366S_PHY_NO_MASK (0x1F<<9) + +#define RTL8366S_PHY_NO_MAX 4 +#define RTL8366S_PHY_PAGE_MAX 7 +#define RTL8366S_PHY_ADDR_MAX 31 + +/* cpu port control reg */ +#define RTL8366S_CPU_CTRL_REG 0x004F +#define RTL8366S_CPU_DRP_BIT 14 +#define RTL8366S_CPU_DRP_MSK 0x4000 +#define RTL8366S_CPU_INSTAG_BIT 15 +#define RTL8366S_CPU_INSTAG_MSK 0x8000 + +/* LED registers*/ +#define RTL8366S_LED_BLINK_REG 0x420 +#define RTL8366S_LED_BLINKRATE_BIT 0 +#define RTL8366S_LED_BLINKRATE_MSK 0x0007 +#define RTL8366S_LED_INDICATED_CONF_REG 0x421 +#define RTL8366S_LED_0_1_FORCE_REG 0x422 +#define RTL8366S_LED_2_3_FORCE_REG 0x423 +#define RTL8366S_LEDCONF_LEDFORCE 0x1F +#define RTL8366S_LED_GROUP_MAX 4 + +#define RTL8366S_GREEN_FEATURE_REG 0x000A +#define RTL8366S_GREEN_FEATURE_TX_BIT 3 +#define RTL8366S_GREEN_FEATURE_TX_MSK 0x0008 +#define RTL8366S_GREEN_FEATURE_RX_BIT 4 +#define RTL8366S_GREEN_FEATURE_RX_MSK 0x0010 + +#define RTL8366S_MODEL_ID_REG 0x5C +#define RTL8366S_REV_ID_REG 0x5D +#define RTL8366S_MODEL_8366SR 0x6027 +#define RTL8366S_MODEL_8366RB 0x5937 + +#endif diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c new file mode 100644 index 0000000..e3c5316 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c @@ -0,0 +1,786 @@ +/* + * (C) Copyright 2010 + * Michael Kurz <michi.kurz@googlemail.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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <net.h> +#include <netdev.h> +#include <miiphy.h> +#include MII_GPIOINCLUDE + +#include "rtl8366.h" + +#ifdef DEBUG_RTL8366 + #define DBG(fmt,args...) printf (fmt ,##args) +#else + #define DBG(fmt,args...) +#endif + + +//------------------------------------------------------------------- +// Soft SMI functions +//------------------------------------------------------------------- + +#define DELAY 2 + +static void smi_init(void) +{ + MII_SDAINPUT; + MII_SCKINPUT; + + MII_SETSDA(1); + MII_SETSCK(1); + + udelay(20); +} + +static void smi_start(void) +{ +/* + * rtl8366 chip needs a extra clock with + * SDA high before start condition + */ + + /* set gpio pins output */ + MII_SDAOUTPUT; + MII_SCKOUTPUT; + udelay(DELAY); + + /* set initial state: SCK:0, SDA:1 */ + MII_SETSCK(0); + MII_SETSDA(1); + udelay(DELAY); + + /* toggle clock */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + + /* start condition */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSDA(0); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + MII_SETSDA(1); +} + +static void smi_stop(void) +{ +/* + * rtl8366 chip needs a extra clock with + * SDA high after stop condition + */ + + /* stop condition */ + udelay(DELAY); + MII_SETSDA(0); + MII_SETSCK(1); + udelay(DELAY); + MII_SETSDA(1); + udelay(DELAY); + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + + /* toggle clock */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + udelay(DELAY); + MII_SETSCK(1); + + /* set gpio pins input */ + MII_SDAINPUT; + MII_SCKINPUT; +} + +static void smi_writeBits(uint32_t data, uint8_t length) +{ + uint8_t test; + + for( ; length > 0; length--) { + udelay(DELAY); + + /* output data */ + test = (((data & (1 << (length - 1))) != 0) ? 1 : 0); + MII_SETSDA(test); + udelay(DELAY); + + /* toogle clock */ + MII_SETSCK(1); + udelay(DELAY); + MII_SETSCK(0); + } +} + +static uint32_t smi_readBits(uint8_t length) +{ + uint32_t ret; + + MII_SDAINPUT; + + for(ret = 0 ; length > 0; length--) { + udelay(DELAY); + + ret <<= 1; + + /* toogle clock */ + MII_SETSCK(1); + udelay(DELAY); + ret |= MII_GETSDA; + MII_SETSCK(0); + } + + MII_SDAOUTPUT; + + return ret; +} + +static int smi_waitAck(void) +{ + uint32_t retry = 0; + + while (smi_readBits(1)) { + if (retry++ == 5) + return -1; + } + + return 0; + +} + +static int smi_read(uint32_t reg, uint32_t *data) +{ + uint32_t rawData; + + /* send start condition */ + smi_start(); + /* send CTRL1 code: 0b1010*/ + smi_writeBits(0x0a, 4); + /* send CTRL2 code: 0b100 */ + smi_writeBits(0x04, 3); + /* send READ command */ + smi_writeBits(0x01, 1); + + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send address low */ + smi_writeBits(reg & 0xFF, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + /* send address high */ + smi_writeBits((reg & 0xFF00) >> 8, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* read data low */ + rawData = (smi_readBits(8) & 0xFF); + /* send ACK */ + smi_writeBits(0, 1); + /* read data high */ + rawData |= (smi_readBits(8) & 0xFF) << 8; + /* send NACK */ + smi_writeBits(1, 1); + + /* send stop condition */ + smi_stop(); + + if (data) + *data = rawData; + + return 0; +} + +static int smi_write(uint32_t reg, uint32_t data) +{ + /* send start condition */ + smi_start(); + /* send CTRL1 code: 0b1010*/ + smi_writeBits(0x0a, 4); + /* send CTRL2 code: 0b100 */ + smi_writeBits(0x04, 3); + /* send WRITE command */ + smi_writeBits(0x00, 1); + + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send address low */ + smi_writeBits(reg & 0xFF, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + /* send address high */ + smi_writeBits((reg & 0xFF00) >> 8, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send data low */ + smi_writeBits(data & 0xFF, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + /* send data high */ + smi_writeBits((data & 0xFF00) >> 8, 8); + /* wait for ACK */ + if (smi_waitAck()) + return -1; + + /* send stop condition */ + smi_stop(); + + return 0; +} + + +//------------------------------------------------------------------- +// Switch register read / write functions +//------------------------------------------------------------------- +static int rtl8366_readRegister(uint32_t reg, uint16_t *data) +{ + uint32_t regData; + + DBG("rtl8366: read register=%#04x, data=", reg); + + if (smi_read(reg, ®Data)) { + printf("\nrtl8366 smi read failed!\n"); + return -1; + } + + if (data) + *data = regData; + + DBG("%#04x\n", regData); + + return 0; +} + +static int rtl8366_writeRegister(uint32_t reg, uint16_t data) +{ + DBG("rtl8366: write register=%#04x, data=%#04x\n", reg, data); + + if (smi_write(reg, data)) { + printf("rtl8366 smi write failed!\n"); + return -1; + } + + return 0; +} + +static int rtl8366_setRegisterBit(uint32_t reg, uint32_t bitNum, uint32_t value) +{ + uint16_t regData; + + if (bitNum >= 16) + return -1; + + if (rtl8366_readRegister(reg, ®Data)) + return -1; + + if (value) + regData |= (1 << bitNum); + else + regData &= ~(1 << bitNum); + + if (rtl8366_writeRegister(reg, regData)) + return -1; + + return 0; +} + +//------------------------------------------------------------------- +// MII PHY read / write functions +//------------------------------------------------------------------- +static int rtl8366_getPhyReg(uint32_t phyNum, uint32_t reg, uint16_t *data) +{ + uint16_t phyAddr, regData; + + if (phyNum > RTL8366S_PHY_NO_MAX) { + printf("rtl8366s: invalid phy number!\n"); + return -1; + } + + if (phyNum > RTL8366S_PHY_ADDR_MAX) { + printf("rtl8366s: invalid phy register number!\n"); + return -1; + } + + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_READ)) + return -1; + + phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) + | (reg & RTL8366S_PHY_REG_MASK); + if (rtl8366_writeRegister(phyAddr, 0)) + return -1; + + if (rtl8366_readRegister(RTL8366S_PHY_ACCESS_DATA_REG, ®Data)) + return -1; + + if (data) + *data = regData; + + return 0; +} + +static int rtl8366_setPhyReg(uint32_t phyNum, uint32_t reg, uint16_t data) +{ + uint16_t phyAddr; + + if (phyNum > RTL8366S_PHY_NO_MAX) { + printf("rtl8366s: invalid phy number!\n"); + return -1; + } + + if (phyNum > RTL8366S_PHY_ADDR_MAX) { + printf("rtl8366s: invalid phy register number!\n"); + return -1; + } + + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE)) + return -1; + + phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) + | (reg & RTL8366S_PHY_REG_MASK); + if (rtl8366_writeRegister(phyAddr, data)) + return -1; + + return 0; +} + +static int rtl8366_miiread(char *devname, uchar phy_adr, uchar reg, ushort *data) +{ + uint16_t regData; + + DBG("rtl8366_miiread: devname=%s, addr=%#02x, reg=%#02x\n", + devname, phy_adr, reg); + + if (strcmp(devname, RTL8366_DEVNAME) != 0) + return -1; + + if (rtl8366_getPhyReg(phy_adr, reg, ®Data)) { + printf("rtl8366_miiread: write failed!\n"); + return -1; + } + + if (data) + *data = regData; + + return 0; +} + +static int rtl8366_miiwrite(char *devname, uchar phy_adr, uchar reg, ushort data) +{ + DBG("rtl8366_miiwrite: devname=%s, addr=%#02x, reg=%#02x, data=%#04x\n", + devname, phy_adr, reg, data); + + if (strcmp(devname, RTL8366_DEVNAME) != 0) + return -1; + + if (rtl8366_setPhyReg(phy_adr, reg, data)) { + printf("rtl8366_miiwrite: write failed!\n"); + return -1; + } + + return 0; +} + +int rtl8366_mii_register(bd_t *bis) +{ + miiphy_register(strdup(RTL8366_DEVNAME), rtl8366_miiread, + rtl8366_miiwrite); + + return 0; +} + + +//------------------------------------------------------------------- +// Switch management functions +//------------------------------------------------------------------- + +int rtl8366s_setGreenFeature(uint32_t tx, uint32_t rx) +{ + if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, + RTL8366S_GREEN_FEATURE_TX_BIT, tx)) + return -1; + + if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, + RTL8366S_GREEN_FEATURE_RX_BIT, rx)) + return -1; + + return 0; +} + +int rtl8366s_setPowerSaving(uint32_t phyNum, uint32_t enabled) +{ + uint16_t regData; + + if (phyNum > RTL8366S_PHY_NO_MAX) + return -1; + + if (rtl8366_getPhyReg(phyNum, 12, ®Data)) + return -1; + + if (enabled) + regData |= (1 << 12); + else + regData &= ~(1 << 12); + + if (rtl8366_setPhyReg(phyNum, 12, regData)) + return -1; + + return 0; +} + +int rtl8366s_setGreenEthernet(uint32_t greenFeature, uint32_t powerSaving) +{ + uint32_t phyNum, i; + uint16_t regData; + + const uint16_t greenSettings[][2] = + { + {0xBE5B,0x3500}, + {0xBE5C,0xB975}, + {0xBE5D,0xB9B9}, + {0xBE77,0xA500}, + {0xBE78,0x5A78}, + {0xBE79,0x6478} + }; + + if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) + return -1; + + switch (regData) + { + case 0x0000: + for (i = 0; i < 6; i++) { + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) + return -1; + if (rtl8366_writeRegister(greenSettings[i][0], greenSettings[i][1])) + return -1; + } + break; + + case RTL8366S_MODEL_8366SR: + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) + return -1; + if (rtl8366_writeRegister(greenSettings[0][0], greenSettings[0][1])) + return -1; + break; + + default: + printf("rtl8366s_initChip: unsupported chip found!\n"); + return -1; + } + + if (rtl8366s_setGreenFeature(greenFeature, powerSaving)) + return -1; + + for (phyNum = 0; phyNum <= RTL8366S_PHY_NO_MAX; phyNum++) { + if (rtl8366s_setPowerSaving(phyNum, powerSaving)) + return -1; + } + + return 0; +} + +int rtl8366s_setCPUPortMask(uint8_t port, uint32_t enabled) +{ + if(port >= 6){ + printf("rtl8366s_setCPUPortMask: invalid port number\n"); + return -1; + } + + return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, port, enabled); +} + +int rtl8366s_setCPUDisableInsTag(uint32_t enable) +{ + return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, + RTL8366S_CPU_INSTAG_BIT, enable); +} + +int rtl8366s_setCPUDropUnda(uint32_t enable) +{ + return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, + RTL8366S_CPU_DRP_BIT, enable); +} + +int rtl8366s_setCPUPort(uint8_t port, uint32_t noTag, uint32_t dropUnda) +{ + uint32_t i; + + if(port >= 6){ + printf("rtl8366s_setCPUPort: invalid port number\n"); + return -1; + } + + /* reset register */ + for(i = 0; i < 6; i++) + { + if(rtl8366s_setCPUPortMask(i, 0)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); + return -1; + } + } + + if(rtl8366s_setCPUPortMask(port, 1)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); + return -1; + } + + if(rtl8366s_setCPUDisableInsTag(noTag)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUDisableInsTag fail\n"); + return -1; + } + + if(rtl8366s_setCPUDropUnda(dropUnda)){ + printf("rtl8366s_setCPUPort: rtl8366s_setCPUDropUnda fail\n"); + return -1; + } + + return 0; +} + +int rtl8366s_setLedConfig(uint32_t ledNum, uint8_t config) +{ + uint16_t regData; + + if(ledNum >= RTL8366S_LED_GROUP_MAX) { + DBG("rtl8366s_setLedConfig: invalid led group\n"); + return -1; + } + + if(config > RTL8366S_LEDCONF_LEDFORCE) { + DBG("rtl8366s_setLedConfig: invalid led config\n"); + return -1; + } + + if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { + printf("rtl8366s_setLedConfig: failed to get led register!\n"); + return -1; + } + + regData &= ~(0xF << (ledNum * 4)); + regData |= config << (ledNum * 4); + + if (rtl8366_writeRegister(RTL8366S_LED_INDICATED_CONF_REG, regData)) { + printf("rtl8366s_setLedConfig: failed to set led register!\n"); + return -1; + } + + return 0; +} + +int rtl8366s_getLedConfig(uint32_t ledNum, uint8_t *config) +{ + uint16_t regData; + + if(ledNum >= RTL8366S_LED_GROUP_MAX) { + DBG("rtl8366s_getLedConfig: invalid led group\n"); + return -1; + } + + if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { + printf("rtl8366s_getLedConfig: failed to get led register!\n"); + return -1; + } + + if (config) + *config = (regData >> (ledNum * 4)) & 0xF; + + return 0; +} + +int rtl8366s_setLedForceValue(uint32_t group0, uint32_t group1, + uint32_t group2, uint32_t group3) +{ + uint16_t regData; + + regData = (group0 & 0x3F) | ((group1 & 0x3F) << 6); + if (rtl8366_writeRegister(RTL8366S_LED_0_1_FORCE_REG, regData)) { + printf("rtl8366s_setLedForceValue: failed to set led register!\n"); + return -1; + } + + regData = (group2 & 0x3F) | ((group3 & 0x3F) << 6); + if (rtl8366_writeRegister(RTL8366S_LED_2_3_FORCE_REG, regData)) { + printf("rtl8366s_setLedForceValue: failed to set led register!\n"); + return -1; + } + + return 0; +} + +int rtl8366s_initChip(void) +{ + uint32_t ledGroup, i = 0; + uint16_t regData; + uint8_t ledData[RTL8366S_LED_GROUP_MAX]; + const uint16_t (*chipData)[2]; + + const uint16_t chipB[][2] = + { + {0x0000, 0x0038},{0x8100, 0x1B37},{0xBE2E, 0x7B9F},{0xBE2B, 0xA4C8}, + {0xBE74, 0xAD14},{0xBE2C, 0xDC00},{0xBE69, 0xD20F},{0xBE3B, 0xB414}, + {0xBE24, 0x0000},{0xBE23, 0x00A1},{0xBE22, 0x0008},{0xBE21, 0x0120}, + {0xBE20, 0x1000},{0xBE24, 0x0800},{0xBE24, 0x0000},{0xBE24, 0xF000}, + {0xBE23, 0xDF01},{0xBE22, 0xDF20},{0xBE21, 0x101A},{0xBE20, 0xA0FF}, + {0xBE24, 0xF800},{0xBE24, 0xF000},{0x0242, 0x02BF},{0x0245, 0x02BF}, + {0x0248, 0x02BF},{0x024B, 0x02BF},{0x024E, 0x02BF},{0x0251, 0x02BF}, + {0x0230, 0x0A32},{0x0233, 0x0A32},{0x0236, 0x0A32},{0x0239, 0x0A32}, + {0x023C, 0x0A32},{0x023F, 0x0A32},{0x0254, 0x0A3F},{0x0255, 0x0064}, + {0x0256, 0x0A3F},{0x0257, 0x0064},{0x0258, 0x0A3F},{0x0259, 0x0064}, + {0x025A, 0x0A3F},{0x025B, 0x0064},{0x025C, 0x0A3F},{0x025D, 0x0064}, + {0x025E, 0x0A3F},{0x025F, 0x0064},{0x0260, 0x0178},{0x0261, 0x01F4}, + {0x0262, 0x0320},{0x0263, 0x0014},{0x021D, 0x9249},{0x021E, 0x0000}, + {0x0100, 0x0004},{0xBE4A, 0xA0B4},{0xBE40, 0x9C00},{0xBE41, 0x501D}, + {0xBE48, 0x3602},{0xBE47, 0x8051},{0xBE4C, 0x6465},{0x8000, 0x1F00}, + {0x8001, 0x000C},{0x8008, 0x0000},{0x8007, 0x0000},{0x800C, 0x00A5}, + {0x8101, 0x02BC},{0xBE53, 0x0005},{0x8E45, 0xAFE8},{0x8013, 0x0005}, + {0xBE4B, 0x6700},{0x800B, 0x7000},{0xBE09, 0x0E00}, + {0xFFFF, 0xABCD} + }; + + const uint16_t chipDefault[][2] = + { + {0x0242, 0x02BF},{0x0245, 0x02BF},{0x0248, 0x02BF},{0x024B, 0x02BF}, + {0x024E, 0x02BF},{0x0251, 0x02BF}, + {0x0254, 0x0A3F},{0x0256, 0x0A3F},{0x0258, 0x0A3F},{0x025A, 0x0A3F}, + {0x025C, 0x0A3F},{0x025E, 0x0A3F}, + {0x0263, 0x007C},{0x0100, 0x0004}, + {0xBE5B, 0x3500},{0x800E, 0x200F},{0xBE1D, 0x0F00},{0x8001, 0x5011}, + {0x800A, 0xA2F4},{0x800B, 0x17A3},{0xBE4B, 0x17A3},{0xBE41, 0x5011}, + {0xBE17, 0x2100},{0x8000, 0x8304},{0xBE40, 0x8304},{0xBE4A, 0xA2F4}, + {0x800C, 0xA8D5},{0x8014, 0x5500},{0x8015, 0x0004},{0xBE4C, 0xA8D5}, + {0xBE59, 0x0008},{0xBE09, 0x0E00},{0xBE36, 0x1036},{0xBE37, 0x1036}, + {0x800D, 0x00FF},{0xBE4D, 0x00FF}, + {0xFFFF, 0xABCD} + }; + + DBG("rtl8366s_initChip\n"); + + /* save current led config and set to led force */ + for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { + if (rtl8366s_getLedConfig(ledGroup, &ledData[ledGroup])) + return -1; + + if (rtl8366s_setLedConfig(ledGroup, RTL8366S_LEDCONF_LEDFORCE)) + return -1; + } + + if (rtl8366s_setLedForceValue(0,0,0,0)) + return -1; + + if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) + return -1; + + switch (regData) + { + case 0x0000: + chipData = chipB; + break; + + case RTL8366S_MODEL_8366SR: + chipData = chipDefault; + break; + + default: + printf("rtl8366s_initChip: unsupported chip found!\n"); + return -1; + } + + DBG("rtl8366s_initChip: found %x chip\n", regData); + + while ((chipData[i][0] != 0xFFFF) && (chipData[i][1] != 0xABCD)) { + + /* phy settings*/ + if ((chipData[i][0] & 0xBE00) == 0xBE00) { + if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE)) + return -1; + } + + if (rtl8366_writeRegister(chipData[i][0], chipData[i][1])) + return -1; + + i++; + } + + /* chip needs some time */ + udelay(100 * 1000); + + /* restore led config */ + for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { + if (rtl8366s_setLedConfig(ledGroup, ledData[ledGroup])) + return -1; + } + + return 0; +} + +int rtl8366s_initialize(void) +{ + uint16_t regData; + + DBG("rtl8366s_initialize: start setup\n"); + + smi_init(); + + rtl8366_readRegister(RTL8366S_CHIP_ID_REG, ®Data); + DBG("Realtek 8366SR switch ID %#04x\n", regData); + + if (regData != 0x8366) { + printf("rtl8366s_initialize: found unsupported switch\n"); + return -1; + } + + if (rtl8366s_initChip()) { + printf("rtl8366s_initialize: init chip failed\n"); + return -1; + } + + if (rtl8366s_setGreenEthernet(1, 1)) { + printf("rtl8366s_initialize: set green ethernet failed\n"); + return -1; + } + + /* Set port 5 noTag and don't dropUnda */ + if (rtl8366s_setCPUPort(5, 1, 0)) { + printf("rtl8366s_initialize: set CPU port failed\n"); + return -1; + } + + return 0; +} |