summaryrefslogtreecommitdiffstats
path: root/board/freescale/ls1021aqds/eth.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/freescale/ls1021aqds/eth.c')
-rw-r--r--board/freescale/ls1021aqds/eth.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/board/freescale/ls1021aqds/eth.c b/board/freescale/ls1021aqds/eth.c
new file mode 100644
index 0000000000..be351befec
--- /dev/null
+++ b/board/freescale/ls1021aqds/eth.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This file handles the board muxing between the RGMII/SGMII PHYs on
+ * Freescale LS1021AQDS board. The RGMII PHYs are the three on-board 1Gb
+ * ports. The SGMII PHYs are provided by the standard Freescale four-port
+ * SGMII riser card.
+ *
+ * Muxing is handled via the PIXIS BRDCFG4 register. The EMI1 bits control
+ * muxing among the RGMII PHYs and the SGMII PHYs. The value for RGMII depends
+ * on which port is used. The value for SGMII depends on which slot the riser
+ * is inserted in.
+ */
+
+#include <common.h>
+#include <netdev.h>
+#include <asm/arch/fsl_serdes.h>
+#include <fsl_mdio.h>
+#include <tsec.h>
+#include <malloc.h>
+
+#include "../common/sgmii_riser.h"
+#include "../common/qixis.h"
+
+#define EMI1_MASK 0x1f
+#define EMI1_RGMII0 1
+#define EMI1_RGMII1 2
+#define EMI1_RGMII2 3
+#define EMI1_SGMII1 0x1c
+#define EMI1_SGMII2 0x1d
+
+struct ls1021a_mdio {
+ struct mii_dev *realbus;
+};
+
+static void ls1021a_mux_mdio(int addr)
+{
+ u8 brdcfg4;
+
+ brdcfg4 = QIXIS_READ(brdcfg[4]);
+ brdcfg4 &= EMI1_MASK;
+
+ switch (addr) {
+ case EMI1_RGMII0:
+ brdcfg4 |= 0;
+ break;
+ case EMI1_RGMII1:
+ brdcfg4 |= 0x20;
+ break;
+ case EMI1_RGMII2:
+ brdcfg4 |= 0x40;
+ break;
+ case EMI1_SGMII1:
+ brdcfg4 |= 0x60;
+ break;
+ case EMI1_SGMII2:
+ brdcfg4 |= 0x80;
+ break;
+ default:
+ brdcfg4 |= 0xa0;
+ break;
+ }
+
+ QIXIS_WRITE(brdcfg[4], brdcfg4);
+}
+
+static int ls1021a_mdio_read(struct mii_dev *bus, int addr, int devad,
+ int regnum)
+{
+ struct ls1021a_mdio *priv = bus->priv;
+
+ ls1021a_mux_mdio(addr);
+
+ return priv->realbus->read(priv->realbus, addr, devad, regnum);
+}
+
+static int ls1021a_mdio_write(struct mii_dev *bus, int addr, int devad,
+ int regnum, u16 value)
+{
+ struct ls1021a_mdio *priv = bus->priv;
+
+ ls1021a_mux_mdio(addr);
+
+ return priv->realbus->write(priv->realbus, addr, devad, regnum, value);
+}
+
+static int ls1021a_mdio_reset(struct mii_dev *bus)
+{
+ struct ls1021a_mdio *priv = bus->priv;
+
+ return priv->realbus->reset(priv->realbus);
+}
+
+static int ls1021a_mdio_init(char *realbusname, char *fakebusname)
+{
+ struct ls1021a_mdio *lsmdio;
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ printf("Failed to allocate LS102xA MDIO bus\n");
+ return -1;
+ }
+
+ lsmdio = malloc(sizeof(*lsmdio));
+ if (!lsmdio) {
+ printf("Failed to allocate LS102xA private data\n");
+ free(bus);
+ return -1;
+ }
+
+ bus->read = ls1021a_mdio_read;
+ bus->write = ls1021a_mdio_write;
+ bus->reset = ls1021a_mdio_reset;
+ sprintf(bus->name, fakebusname);
+
+ lsmdio->realbus = miiphy_get_dev_by_name(realbusname);
+
+ if (!lsmdio->realbus) {
+ printf("No bus with name %s\n", realbusname);
+ free(bus);
+ free(lsmdio);
+ return -1;
+ }
+
+ bus->priv = lsmdio;
+
+ return mdio_register(bus);
+}
+
+int board_eth_init(bd_t *bis)
+{
+ struct fsl_pq_mdio_info mdio_info;
+ struct tsec_info_struct tsec_info[3];
+ int num = 0;
+
+#ifdef CONFIG_TSEC1
+ SET_STD_TSEC_INFO(tsec_info[num], 1);
+ if (is_serdes_configured(SGMII_TSEC1)) {
+ puts("eTSEC1 is in sgmii mode\n");
+ tsec_info[num].flags |= TSEC_SGMII;
+ tsec_info[num].mii_devname = "LS1021A_SGMII_MDIO";
+ } else {
+ tsec_info[num].mii_devname = "LS1021A_RGMII_MDIO";
+ }
+ num++;
+#endif
+#ifdef CONFIG_TSEC2
+ SET_STD_TSEC_INFO(tsec_info[num], 2);
+ if (is_serdes_configured(SGMII_TSEC2)) {
+ puts("eTSEC2 is in sgmii mode\n");
+ tsec_info[num].flags |= TSEC_SGMII;
+ tsec_info[num].mii_devname = "LS1021A_SGMII_MDIO";
+ } else {
+ tsec_info[num].mii_devname = "LS1021A_RGMII_MDIO";
+ }
+ num++;
+#endif
+#ifdef CONFIG_TSEC3
+ SET_STD_TSEC_INFO(tsec_info[num], 3);
+ tsec_info[num].mii_devname = "LS1021A_RGMII_MDIO";
+ num++;
+#endif
+ if (!num) {
+ printf("No TSECs initialized\n");
+ return 0;
+ }
+
+#ifdef CONFIG_FSL_SGMII_RISER
+ fsl_sgmii_riser_init(tsec_info, num);
+#endif
+
+ mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR;
+ mdio_info.name = DEFAULT_MII_NAME;
+
+ fsl_pq_mdio_init(bis, &mdio_info);
+
+ /* Register the virtual MDIO front-ends */
+ ls1021a_mdio_init(DEFAULT_MII_NAME, "LS1021A_RGMII_MDIO");
+ ls1021a_mdio_init(DEFAULT_MII_NAME, "LS1021A_SGMII_MDIO");
+
+ tsec_eth_init(bis, tsec_info, num);
+
+ return pci_eth_init(bis);
+}
OpenPOWER on IntegriCloud