This patch adds simple support for KS8993M and KS8995MA managed switches.
It uses SPI interface for configuration (as everything cannot be configured
through MII). Switch can be configured to either regular switch or to
"router mode" so that every port (except the host port) has it's own VLAN
("port based VLAN").

Signed-off-by: Sami Kantoluoto <sami.kantolu...@embedtronics.fi>
---
 drivers/net/phy/Makefile  |    1 +
 drivers/net/phy/ks899xm.c |  189 +++++++++++++++++++++++++++++++++
 drivers/net/phy/ks899xm.h |  255 +++++++++++++++++++++++++++++++++++++++++++++
 include/netdev.h          |   15 +++
 4 files changed, 460 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/phy/ks899xm.c
 create mode 100644 drivers/net/phy/ks899xm.h

diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3b92614..d91244c 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
 LIB    := $(obj)libphy.a
 
 COBJS-$(CONFIG_BITBANGMII) += miiphybb.o
+COBJS-$(CONFIG_KS899XM_SWITCH) += ks899xm.o
 COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o
 
 COBJS  := $(COBJS-y)
diff --git a/drivers/net/phy/ks899xm.c b/drivers/net/phy/ks899xm.c
new file mode 100644
index 0000000..87e47c7
--- /dev/null
+++ b/drivers/net/phy/ks899xm.c
@@ -0,0 +1,189 @@
+/*
+ * (C) Copyright 2009
+ * Sami Kantoluoto <sami.kantolu...@embedtronics.fi>
+ * Embedtronics Oy <www.embedtronics.fi>
+ *
+ * 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 <netdev.h>
+#include <spi.h>
+#include "ks899xm.h"
+
+static unsigned int ks_cmd (struct spi_slave *ss,
+                           unsigned rdwr, unsigned reg, unsigned value,
+                           unsigned *retvalue)
+{
+       unsigned char cmd[4] = { rdwr, reg, value }, rsp[4];
+       int ret;
+
+       ret = spi_xfer(ss, 32, cmd, rsp, SPI_XFER_BEGIN | SPI_XFER_END);
+
+       if (ret != 0) {
+               return KS_ERROR;
+       }
+
+       if (retvalue) {
+               *retvalue = rsp[2];
+       }
+
+       return KS_OK;
+}
+
+static unsigned int ks_write_reg (struct spi_slave *ss,
+                                 unsigned reg, unsigned value)
+{
+       /*printf("%s: reg=%02x, value=%02x\n", __FUNCTION__, reg, value); */
+       return ks_cmd (ss, KS_WR_DATA, reg, value, 0);
+}
+
+static unsigned int ks_read_reg (struct spi_slave *ss,
+                                unsigned reg, unsigned *value)
+{
+       int ret = ks_cmd (ss, KS_RD_DATA, reg, 0, value);
+       /*printf("%s: reg=%02x, value=%02x, ret=%d\n", __FUNCTION__, reg, 
*value, ret); */
+       return ret;
+}
+
+static unsigned int ks_ind_wr (struct spi_slave *ss,
+                              unsigned table, unsigned addr,
+                              const unsigned char *data, int dlen)
+{
+       int i, ret;
+
+       for (ret = KS_OK, i = 9 - dlen; ret == KS_OK && (i <= 8); i++) {
+               ret = ks_write_reg (ss, KS_IDR8 + i, *data++);
+       }
+
+       if (ret == KS_OK) {
+               ret =
+                   ks_write_reg (ss, KS_IAC0,
+                                 (table & KS_IAC0_TBL) | ((addr >> 8) &
+                                                          KS_IAC0_ADDR_HIGH));
+       }
+
+       if (ret == KS_OK) {
+               ret = ks_write_reg (ss, KS_IAC1, addr & 0xff);
+       }
+
+       return ret;
+}
+
+static int ks_write_vtab (struct spi_slave *ss,
+                         unsigned ndx, unsigned vid, unsigned fid,
+                         unsigned members)
+{
+       unsigned char buf[3] = {
+               0x20 | (members & 0x1F),
+               (fid << 4) | ((vid >> 8) & 0xF),
+               vid & 0xFF
+       };
+       return ks_ind_wr (ss, KS_IAC0_TBL_VLAN, ndx, buf, 3);
+}
+
+int ks899xm_switch_initialize(const struct ks899xm_config *swconfig)
+{
+       struct spi_slave *ss;
+       int ret = -1, i, nports = -1;
+       unsigned id0, id1;
+
+       /* check arguments */
+       if (swconfig->vlancfg != KS899XM_VLANCFG_DEFAULT
+           && swconfig->vlancfg != KS899XM_VLANCFG_ROUTER)
+               goto done;
+
+       /* prepare spi */
+       ss = spi_setup_slave(swconfig->spibus, swconfig->spics,
+                            10000000, SPI_MODE_0);
+       if (!ss)
+               goto done;
+       if (spi_claim_bus(ss) != 0)
+               goto done_2;
+
+       /* get chip id */
+       if (ks_read_reg (ss, KS_ID0, &id0) != KS_OK
+           || ks_read_reg (ss, KS_ID1, &id1) != KS_OK)
+               goto done_3;
+
+       /* check chip id */
+       switch (id0) {
+       case 0x93:
+       case 0x95:
+               if (!(id1 & 0xF0)) {
+                       nports = id0 & 0xf;
+                       printf ("Micrel %s detected, revision: 0x%X\n",
+                               nports == 5 ? "KS8995MA" : "KS8993M",
+                               (id1 & 0x0e) >> 1);
+                       break;
+               }
+               /* fall through: */
+       default:
+               printf ("unknown chip, id0:%02x, id1=%02x\n", id0, id1);
+               goto done_3;
+       }
+
+       /* enable flow control */
+       if (ks_write_reg(ss, KS_GC3,
+                        swconfig->vlancfg == KS899XM_VLANCFG_ROUTER
+                        ? KS_GC3_802_1Q_VLAN : 0) != KS_OK
+           || ks_write_reg(ss, KS_GC4, KS_GC4_MII_FLOW_ENA) != KS_OK)
+               goto done_3;
+
+       if (swconfig->vlancfg == KS899XM_VLANCFG_ROUTER) {
+               /* configure vlans */
+               for (i = 0; i < (nports - 1); i++) {
+                       if (ks_write_vtab (ss, i, i + 1, i + 1,
+                                          (1 << (nports - 1)) | (1 << i)) != 
KS_OK)
+                               goto done_3;
+                       if (ks_write_reg (ss, KS_P1 + 16 * i + KS_P_CR0,
+                                         KS_P_CR0_TAG_REMOVAL) != KS_OK ||
+                           ks_write_reg (ss, KS_P1 + 16 * i + KS_P_CR1,
+                                         1 << (nports - 1)) != KS_OK ||
+                           ks_write_reg (ss, KS_P1 + 16 * i + KS_P_CR2,
+                                         KS_P_CR2_VLAN_FILTERING |
+                                         KS_P_CR2_TRANSMIT_ENA |
+                                         KS_P_CR2_RECEIVE_ENA) != KS_OK)
+                               goto done_3;
+               }
+               /* configure host port too */
+               if (ks_write_reg (ss, KS_P1 + 16 * i + KS_P_CR0,
+                                 KS_P_CR0_TAG_INSERTION) != KS_OK ||
+                   ks_write_reg (ss, KS_P1 + 16 * i + KS_P_CR1,
+                                 (1 << i) - 1) != KS_OK ||
+                   ks_write_reg (ss, KS_P1 + 16 * i + KS_P_CR2,
+                                 KS_P_CR2_TRANSMIT_ENA |
+                                 KS_P_CR2_RECEIVE_ENA) != KS_OK)
+                       goto done_3;
+       }
+       if (ks_write_reg (ss, KS_GC9, 0) != KS_OK)
+               goto done_3;
+
+       /* finally start the switch */
+       if (ks_write_reg (ss, KS_ID1, KS_ID1_START_SWITCH) == KS_OK) {
+               ret = 0;
+       }
+
+done_3:
+       spi_release_bus(ss);
+done_2:
+       spi_free_slave(ss);
+done:
+       return ret;
+}
diff --git a/drivers/net/phy/ks899xm.h b/drivers/net/phy/ks899xm.h
new file mode 100644
index 0000000..d3d6591
--- /dev/null
+++ b/drivers/net/phy/ks899xm.h
@@ -0,0 +1,255 @@
+/*
+ * (C) Copyright 2009
+ * Sami Kantoluoto <sami.kantolu...@embedtronics.fi>
+ * Embedtronics Oy <www.embedtronics.fi>
+ *
+ * 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        _KS899XMA_H
+#define        _KS899XMA_H     1
+
+#define        KS_OK           0
+#define        KS_ERROR        -1
+
+#define        KS_RD_DATA      0x03
+#define        KS_WR_DATA      0x02
+
+enum {
+       KS_ID0 = 0,
+       KS_ID1,
+       KS_GC0,
+       KS_GC1,
+       KS_GC2,
+       KS_GC3,
+       KS_GC4,
+       KS_GC5,
+       KS_GC6,
+       KS_GC7,
+       KS_GC8,
+       KS_GC9,
+
+       KS_P_CR0 = 0,
+       KS_P_CR1,
+       KS_P_CR2,
+       KS_P_CR3,
+       KS_P_CR4,
+       KS_P_CR5,
+       KS_P_CR6,
+       KS_P_CR7,
+       KS_P_CR8,
+       KS_P_CR9,
+       KS_P_CR10,
+       KS_P_CR11,
+       KS_P_CR12,
+       KS_P_CR13,
+       KS_P_SR0,
+       KS_P_CR14,
+
+       KS_P1 = 16,
+       KS_P2 = 32,
+       KS_P3 = 48,
+       KS_P4 = 64,
+       KS_P5 = 80,
+
+       KS_TOS_PCR0 = 96,
+       KS_TOS_PCR1,
+       KS_TOS_PCR2,
+       KS_TOS_PCR3,
+       KS_TOS_PCR4,
+       KS_TOS_PCR5,
+       KS_TOS_PCR6,
+       KS_TOS_PCR7,
+
+       KS_TOS_MAC0,
+       KS_TOS_MAC1,
+       KS_TOS_MAC2,
+       KS_TOS_MAC3,
+       KS_TOS_MAC4,
+       KS_TOS_MAC5,
+
+       KS_IAC0,
+       KS_IAC1,
+       KS_IDR8,
+       KS_IDR7,
+       KS_IDR6,
+       KS_IDR5,
+       KS_IDR4,
+       KS_IDR3,
+       KS_IDR2,
+       KS_IDR1,
+       KS_IDR0,
+
+       KS_DTS0,
+       KS_DTS1,
+       KS_DTC0,
+       KS_DTC1,
+       KS_ATC0,
+       KS_ATC1,
+       KS_ATS,
+};
+
+#define        KS_ID0_FAMILY_ID                0xFF
+
+#define        KS_ID1_CHIP_ID          0xF0
+#define        KS_ID1_CHIP_ID_B                4
+#define        KS_ID1_REV_ID           0x0E
+#define        KS_ID1_START_SWITCH     0x01
+
+#define        KS_GC0_802_1P_PRIO              0x70
+#define        KS_GC0_802_1P_PRIO_B    4
+#define        KS_GC0_ENABLE_PHY_MII   0x08
+#define        KS_GC0_SHARED_BUFFER    0x04
+#define        KS_GC0_UNH_MODE         0x02
+#define        KS_GC0_LINK_CHANGE_AGE  0x01
+
+#define        KS_GC1_PASS_ALL         0x80
+#define        KS_GC1_PROMISCUOUS              GC1_PASS_ALL
+#define        KS_GC1_TX_FLOW_CTL_DISABLE      0x20
+#define        KS_GC1_RX_FLOW_CTL_DISABLE      0x10
+#define        KS_GC1_FRAME_LENGTH_CHK 0x08
+#define        KS_GC1_AGING            0x04
+#define        KS_GC1_FAST_AGING               0x02
+#define        KS_GC1_AGGRESSIVE_BACK_OFF      0x01
+
+#define        KS_GC2_UNICAST_VLAN_DISC        0x80
+#define        KS_GC2_MULTICAST_STORM_DIS      0x40
+#define        KS_GC2_BACK_PRESSURE_MODE       0x20
+#define        KS_GC2_FAIR_MODE                0x10
+#define        KS_GC2_NO_EXCESSIVE_DROP        0x08
+#define        KS_GC2_HUGE_PACKET              0x04
+#define        KS_GC2_DISABLE_LENGTH_CHK       0x02
+#define        KS_GC2_PRIORITY_BUF     0x01
+
+#define        KS_GC3_802_1Q_VLAN              0x80
+#define        KS_GC3_IGMP_SNOOP               0x40
+#define        KS_GC3_MII_DIRECT_MODE  0x20
+#define        KS_GC3_MII_PRE_TAG              0x10
+#define        KS_GC3_PRIO_SCHEME_SEL  0x0C
+#define        KS_GC3_PRIO_SCHEME_HIGH 0x00
+#define        KS_GC3_PRIO_SCHEME_10_1 0x04
+#define        KS_GC3_PRIO_SCHEME_5_1  0x08
+#define        KS_GC3_PRIO_SCHEME_2_1  0x0C
+#define        KS_GC3_TAG_MASK         0x02
+#define        KS_GC3_RX_AND_TX_SNIFF  0x01
+
+#define        KS_GC4_MII_BACK_PRESSURE        0x80
+#define        KS_GC4_MII_HALF_DUPLEX  0x40
+#define        KS_GC4_MII_FLOW_ENA     0x20
+#define        KS_GC4_MII_10_MBPS              0x10
+#define        KS_GC4_NULL_VID_REPLACE 0x08
+#define        KS_GC4_BCAST_STORM_PROT 0x07
+#define        KS_GC4_BCAST_STORM_PROT_B       0
+
+#define        KS_GC5_BCAST_STORM_PROT 0xFF
+#define        KS_GC5_BCAST_STORM_PROT_B       0
+
+#define        KS_GC9_PHY_PWR_SAVE     0x08
+#define        KS_GC9_PHY_LED_MODE     0x02
+#define        KS_GC9_TPID_MODE                0x01
+
+#define        KS_P_CR0_BCAST_STORM_PROT_ENA   0x80
+#define        KS_P_CR0_DIFFSERV_PRIO_ENA      0x40
+#define        KS_P_CR0_802_1P_PRIO_ENA        0x20
+#define        KS_P_CR0_CLASSIFICATION_ENA     0x10
+#define        KS_P_CR0_TAG_INSERTION  0x04
+#define        KS_P_CR0_TAG_REMOVAL    0x02
+#define        KS_P_CR0_PRIO_ENA               0x01
+
+#define        KS_P_CR1_SNIFFER_PORT   0x80
+#define        KS_P_CR1_RECEIVE_SNIFF  0x40
+#define        KS_P_CR1_TRANSMIT_SNIFF 0x20
+#define        KS_P_CR1_PORT_VLAN_MASK 0x1F
+
+#define        KS_P_CR2_VLAN_FILTERING 0x40
+#define        KS_P_CR2_DISCARD_NON_PVID       0x20
+#define        KS_P_CR2_FORCE_FLOW_CTL 0x10
+#define        KS_P_CR2_BACK_PRESURE_ENA       0x08
+#define        KS_P_CR2_TRANSMIT_ENA   0x04
+#define        KS_P_CR2_RECEIVE_ENA    0x02
+#define        KS_P_CR2_LEARNING_DIS   0x01
+
+#define        KS_P_CR7_TX_LOW_PRIO_RATE       0xF0
+#define        KS_P_CR7_TX_HIGH_PRIO_RATE      0x0F
+
+#define        KS_P_CR10_RX_LOW_PRIO_RATE      0xF0
+#define        KS_P_CR10_RX_HIGH_PRIO_RATE     0x0F
+
+#define        KS_P_CR11_RX_DIFF_PRIO_ENA              0x80
+#define        KS_P_CR11_RX_LOW_PRIO_RATE_ENA  0x40
+#define        KS_P_CR11_RX_HIGH_PRIO_RATE_ENA 0x20
+#define        KS_P_CR11_RX_LOW_PRIO_RATE_FLOW 0x10
+#define        KS_P_CR11_RX_HIGH_PRIO_RATE_FLOW        0x08
+#define        KS_P_CR11_TX_DIFF_PRIO_ENA              0x04
+#define        KS_P_CR11_TX_LOW_PRIO_RATE_ENA  0x02
+#define        KS_P_CR11_TX_HIGH_PRIO_RATE_ENA 0x01
+
+#define        KS_P_CR12_AUTO_NEG_DIS          0x80
+#define        KS_P_CR12_100_MBPS                      0x40
+#define        KS_P_CR12_FULL_DUPLEX           0x20
+#define        KS_P_CR12_ADVERTISED_FLOW_CTL   0x10
+#define        KS_P_CR12_ADVERTISED_100_FD     0x08
+#define        KS_P_CR12_ADVERTISED_100_HD     0x04
+#define        KS_P_CR12_ADVERTISED_10_FD              0x02
+#define        KS_P_CR12_ADVERTISED_10_HD              0x01
+
+#define        KS_P_CR13_LED_OFF                       0x80
+#define        KS_P_CR13_TX_DIS                        0x40
+#define        KS_P_CR13_RESTART_AN            0x20
+#define        KS_P_CR13_FAR_END_DIS           0x10
+#define        KS_P_CR13_PWR_DOWN                      0x08
+#define        KS_P_CR13_AUTO_MDI_MDI_X_DIS    0x04
+#define        KS_P_CR13_FORCED_MDI            0x02
+#define        KS_P_CR13_MAC_LOOPBACK          0x01
+
+#define        KS_P_PS0_MDI                    0x80
+#define        KS_P_PS0_AN_DONE                        0x40
+#define        KS_P_PS0_LINK_GOOD                      0x20
+#define        KS_P_PS0_PARTNER_FLOW_CTL_CAP   0x10
+#define        KS_P_PS0_PARTNER_100BT_FD_CAP   0x08
+#define        KS_P_PS0_PARTNER_100BT_HD_CAP   0x04
+#define        KS_P_PS0_PARTNER_10BT_FD_CAP    0x02
+#define        KS_P_PS0_PARTNER_10BT_HD_CAP    0x01
+
+#define        KS_P_CR14_PHY_LOOPBACK          0x80
+#define        KS_P_CR14_REMOTE_LOOPBACK               0x40
+#define        KS_P_CR14_PHY_ISOLATE           0x20
+#define        KS_P_CR14_SOFT_RESET            0x10
+#define        KS_P_CR14_FORCE_LINK            0x08
+#define        KS_P_CR14_FAR_END_FAULT         0x01
+
+#define        KS_IAC0_RD                              0x10
+#define        KS_IAC0_TBL                     0x0C
+#define        KS_IAC0_TBL_STATIC_MAC          0x00
+#define        KS_IAC0_TBL_VLAN                        0x04
+#define        KS_IAC0_TBL_DYNAMIC_MAC         0x08
+#define        KS_IAC0_TBL_MIB_COUNTER         0x0C
+#define        KS_IAC0_ADDR_HIGH                       0x03
+
+typedef union ks_ind_data {
+       u_int8_t Buf[9];
+       struct {
+               u_int8_t _reserved[(72 - 21) / 8];
+               u_int8_t Membership;
+#define        KS_MEMB_VALID   0x20
+               u_int16_t VID;
+       } __attribute__ ((packed)) VLAN;
+} ks_ind_data_t;
+
+#endif /* !_KS899XMA_H */
diff --git a/include/netdev.h b/include/netdev.h
index a50ec67..628de38 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -171,4 +171,19 @@ struct mv88e61xx_config {
 int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig);
 #endif /* CONFIG_MV88E61XX_SWITCH */
 
+#ifdef CONFIG_KS899XM_SWITCH
+enum ks899xm_cfg_vlan {
+       KS899XM_VLANCFG_DEFAULT,
+       KS899XM_VLANCFG_ROUTER
+};
+
+struct ks899xm_config {
+       unsigned spibus, spics;
+       enum ks899xm_cfg_vlan vlancfg;
+};
+
+int ks899xm_switch_initialize(const struct ks899xm_config *swconfig);
+
+#endif /* CONFIG_KS899XM_SWITCH */
+
 #endif /* _NETDEV_H_ */
-- 
1.6.0.4

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

Reply via email to