blob: bf3e08a8cf9dcad6bddcfb072183223c6c7ec682 [file] [log] [blame]
Wang Huan550e3dc2014-09-05 13:52:44 +08001/*
2 * Copyright 2014 Freescale Semiconductor, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 *
6 * This file handles the board muxing between the RGMII/SGMII PHYs on
7 * Freescale LS1021AQDS board. The RGMII PHYs are the three on-board 1Gb
8 * ports. The SGMII PHYs are provided by the standard Freescale four-port
9 * SGMII riser card.
10 *
11 * Muxing is handled via the PIXIS BRDCFG4 register. The EMI1 bits control
12 * muxing among the RGMII PHYs and the SGMII PHYs. The value for RGMII depends
13 * on which port is used. The value for SGMII depends on which slot the riser
14 * is inserted in.
15 */
16
17#include <common.h>
18#include <netdev.h>
19#include <asm/arch/fsl_serdes.h>
20#include <fsl_mdio.h>
21#include <tsec.h>
22#include <malloc.h>
23
24#include "../common/sgmii_riser.h"
25#include "../common/qixis.h"
26
27#define EMI1_MASK 0x1f
28#define EMI1_RGMII0 1
29#define EMI1_RGMII1 2
30#define EMI1_RGMII2 3
31#define EMI1_SGMII1 0x1c
32#define EMI1_SGMII2 0x1d
33
34struct ls1021a_mdio {
35 struct mii_dev *realbus;
36};
37
38static void ls1021a_mux_mdio(int addr)
39{
40 u8 brdcfg4;
41
42 brdcfg4 = QIXIS_READ(brdcfg[4]);
43 brdcfg4 &= EMI1_MASK;
44
45 switch (addr) {
46 case EMI1_RGMII0:
47 brdcfg4 |= 0;
48 break;
49 case EMI1_RGMII1:
50 brdcfg4 |= 0x20;
51 break;
52 case EMI1_RGMII2:
53 brdcfg4 |= 0x40;
54 break;
55 case EMI1_SGMII1:
56 brdcfg4 |= 0x60;
57 break;
58 case EMI1_SGMII2:
59 brdcfg4 |= 0x80;
60 break;
61 default:
62 brdcfg4 |= 0xa0;
63 break;
64 }
65
66 QIXIS_WRITE(brdcfg[4], brdcfg4);
67}
68
69static int ls1021a_mdio_read(struct mii_dev *bus, int addr, int devad,
70 int regnum)
71{
72 struct ls1021a_mdio *priv = bus->priv;
73
74 ls1021a_mux_mdio(addr);
75
76 return priv->realbus->read(priv->realbus, addr, devad, regnum);
77}
78
79static int ls1021a_mdio_write(struct mii_dev *bus, int addr, int devad,
80 int regnum, u16 value)
81{
82 struct ls1021a_mdio *priv = bus->priv;
83
84 ls1021a_mux_mdio(addr);
85
86 return priv->realbus->write(priv->realbus, addr, devad, regnum, value);
87}
88
89static int ls1021a_mdio_reset(struct mii_dev *bus)
90{
91 struct ls1021a_mdio *priv = bus->priv;
92
93 return priv->realbus->reset(priv->realbus);
94}
95
96static int ls1021a_mdio_init(char *realbusname, char *fakebusname)
97{
98 struct ls1021a_mdio *lsmdio;
99 struct mii_dev *bus = mdio_alloc();
100
101 if (!bus) {
102 printf("Failed to allocate LS102xA MDIO bus\n");
103 return -1;
104 }
105
106 lsmdio = malloc(sizeof(*lsmdio));
107 if (!lsmdio) {
108 printf("Failed to allocate LS102xA private data\n");
109 free(bus);
110 return -1;
111 }
112
113 bus->read = ls1021a_mdio_read;
114 bus->write = ls1021a_mdio_write;
115 bus->reset = ls1021a_mdio_reset;
Ben Whitten192bc692015-12-30 13:05:58 +0000116 strcpy(bus->name, fakebusname);
Wang Huan550e3dc2014-09-05 13:52:44 +0800117
118 lsmdio->realbus = miiphy_get_dev_by_name(realbusname);
119
120 if (!lsmdio->realbus) {
121 printf("No bus with name %s\n", realbusname);
122 free(bus);
123 free(lsmdio);
124 return -1;
125 }
126
127 bus->priv = lsmdio;
128
129 return mdio_register(bus);
130}
131
132int board_eth_init(bd_t *bis)
133{
134 struct fsl_pq_mdio_info mdio_info;
135 struct tsec_info_struct tsec_info[3];
136 int num = 0;
137
138#ifdef CONFIG_TSEC1
139 SET_STD_TSEC_INFO(tsec_info[num], 1);
140 if (is_serdes_configured(SGMII_TSEC1)) {
141 puts("eTSEC1 is in sgmii mode\n");
142 tsec_info[num].flags |= TSEC_SGMII;
143 tsec_info[num].mii_devname = "LS1021A_SGMII_MDIO";
144 } else {
145 tsec_info[num].mii_devname = "LS1021A_RGMII_MDIO";
146 }
147 num++;
148#endif
149#ifdef CONFIG_TSEC2
150 SET_STD_TSEC_INFO(tsec_info[num], 2);
151 if (is_serdes_configured(SGMII_TSEC2)) {
152 puts("eTSEC2 is in sgmii mode\n");
153 tsec_info[num].flags |= TSEC_SGMII;
154 tsec_info[num].mii_devname = "LS1021A_SGMII_MDIO";
155 } else {
156 tsec_info[num].mii_devname = "LS1021A_RGMII_MDIO";
157 }
158 num++;
159#endif
160#ifdef CONFIG_TSEC3
161 SET_STD_TSEC_INFO(tsec_info[num], 3);
162 tsec_info[num].mii_devname = "LS1021A_RGMII_MDIO";
163 num++;
164#endif
165 if (!num) {
166 printf("No TSECs initialized\n");
167 return 0;
168 }
169
170#ifdef CONFIG_FSL_SGMII_RISER
171 fsl_sgmii_riser_init(tsec_info, num);
172#endif
173
174 mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR;
175 mdio_info.name = DEFAULT_MII_NAME;
176
177 fsl_pq_mdio_init(bis, &mdio_info);
178
179 /* Register the virtual MDIO front-ends */
180 ls1021a_mdio_init(DEFAULT_MII_NAME, "LS1021A_RGMII_MDIO");
181 ls1021a_mdio_init(DEFAULT_MII_NAME, "LS1021A_SGMII_MDIO");
182
183 tsec_eth_init(bis, tsec_info, num);
184
185 return pci_eth_init(bis);
186}