Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/* Copyright Altera Corporation (C) 2016. All rights reserved.
  2 *
  3 * This program is free software; you can redistribute it and/or modify
  4 * it under the terms of the GNU General Public License, version 2,
  5 * as published by the Free Software Foundation.
  6 *
  7 * This program is distributed in the hope that it will be useful,
  8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10 * GNU General Public License for more details.
 11 *
 12 * You should have received a copy of the GNU General Public License
 13 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 14 *
 15 * Author: Tien Hock Loh <thloh@altera.com>
 16 */
 17
 18#include <linux/mfd/syscon.h>
 19#include <linux/of.h>
 20#include <linux/of_address.h>
 21#include <linux/of_net.h>
 22#include <linux/phy.h>
 23#include <linux/regmap.h>
 24#include <linux/reset.h>
 25#include <linux/stmmac.h>
 26
 27#include "stmmac.h"
 28#include "stmmac_platform.h"
 29#include "altr_tse_pcs.h"
 30
 31#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII	0
 32#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII		BIT(1)
 33#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII		BIT(2)
 34#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH		2
 35#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK			GENMASK(1, 0)
 36
 37#define TSE_PCS_CONTROL_AN_EN_MASK			BIT(12)
 38#define TSE_PCS_CONTROL_REG				0x00
 39#define TSE_PCS_CONTROL_RESTART_AN_MASK			BIT(9)
 40#define TSE_PCS_CTRL_AUTONEG_SGMII			0x1140
 41#define TSE_PCS_IF_MODE_REG				0x28
 42#define TSE_PCS_LINK_TIMER_0_REG			0x24
 43#define TSE_PCS_LINK_TIMER_1_REG			0x26
 44#define TSE_PCS_SIZE					0x40
 45#define TSE_PCS_STATUS_AN_COMPLETED_MASK		BIT(5)
 46#define TSE_PCS_STATUS_LINK_MASK			0x0004
 47#define TSE_PCS_STATUS_REG				0x02
 48#define TSE_PCS_SGMII_SPEED_1000			BIT(3)
 49#define TSE_PCS_SGMII_SPEED_100				BIT(2)
 50#define TSE_PCS_SGMII_SPEED_10				0x0
 51#define TSE_PCS_SW_RST_MASK				0x8000
 52#define TSE_PCS_PARTNER_ABILITY_REG			0x0A
 53#define TSE_PCS_PARTNER_DUPLEX_FULL			0x1000
 54#define TSE_PCS_PARTNER_DUPLEX_HALF			0x0000
 55#define TSE_PCS_PARTNER_DUPLEX_MASK			0x1000
 56#define TSE_PCS_PARTNER_SPEED_MASK			GENMASK(11, 10)
 57#define TSE_PCS_PARTNER_SPEED_1000			BIT(11)
 58#define TSE_PCS_PARTNER_SPEED_100			BIT(10)
 59#define TSE_PCS_PARTNER_SPEED_10			0x0000
 60#define TSE_PCS_PARTNER_SPEED_1000			BIT(11)
 61#define TSE_PCS_PARTNER_SPEED_100			BIT(10)
 62#define TSE_PCS_PARTNER_SPEED_10			0x0000
 63#define TSE_PCS_SGMII_SPEED_MASK			GENMASK(3, 2)
 64#define TSE_PCS_SGMII_LINK_TIMER_0			0x0D40
 65#define TSE_PCS_SGMII_LINK_TIMER_1			0x0003
 66#define TSE_PCS_SW_RESET_TIMEOUT			100
 67#define TSE_PCS_USE_SGMII_AN_MASK			BIT(1)
 68#define TSE_PCS_USE_SGMII_ENA				BIT(0)
 69#define TSE_PCS_IF_USE_SGMII				0x03
 70
 71#define SGMII_ADAPTER_CTRL_REG				0x00
 72#define SGMII_ADAPTER_DISABLE				0x0001
 73#define SGMII_ADAPTER_ENABLE				0x0000
 74
 75#define AUTONEGO_LINK_TIMER				20
 76
 77static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs)
 78{
 79	int counter = 0;
 80	u16 val;
 81
 82	val = readw(base + TSE_PCS_CONTROL_REG);
 83	val |= TSE_PCS_SW_RST_MASK;
 84	writew(val, base + TSE_PCS_CONTROL_REG);
 85
 86	while (counter < TSE_PCS_SW_RESET_TIMEOUT) {
 87		val = readw(base + TSE_PCS_CONTROL_REG);
 88		val &= TSE_PCS_SW_RST_MASK;
 89		if (val == 0)
 90			break;
 91		counter++;
 92		udelay(1);
 93	}
 94	if (counter >= TSE_PCS_SW_RESET_TIMEOUT) {
 95		dev_err(pcs->dev, "PCS could not get out of sw reset\n");
 96		return -ETIMEDOUT;
 97	}
 98
 99	return 0;
100}
101
102int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs)
103{
104	int ret = 0;
105
106	writew(TSE_PCS_IF_USE_SGMII, base + TSE_PCS_IF_MODE_REG);
107
108	writew(TSE_PCS_CTRL_AUTONEG_SGMII, base + TSE_PCS_CONTROL_REG);
109
110	writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG);
111	writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG);
112
113	ret = tse_pcs_reset(base, pcs);
114	if (ret == 0)
115		writew(SGMII_ADAPTER_ENABLE,
116		       pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
117
118	return ret;
119}
120
121static void pcs_link_timer_callback(struct tse_pcs *pcs)
122{
123	u16 val = 0;
124	void __iomem *tse_pcs_base = pcs->tse_pcs_base;
125	void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
126
127	val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
128	val &= TSE_PCS_STATUS_LINK_MASK;
129
130	if (val != 0) {
131		dev_dbg(pcs->dev, "Adapter: Link is established\n");
132		writew(SGMII_ADAPTER_ENABLE,
133		       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
134	} else {
135		mod_timer(&pcs->aneg_link_timer, jiffies +
136			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
137	}
138}
139
140static void auto_nego_timer_callback(struct tse_pcs *pcs)
141{
142	u16 val = 0;
143	u16 speed = 0;
144	u16 duplex = 0;
145	void __iomem *tse_pcs_base = pcs->tse_pcs_base;
146	void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
147
148	val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
149	val &= TSE_PCS_STATUS_AN_COMPLETED_MASK;
150
151	if (val != 0) {
152		dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n");
153		val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG);
154		speed = val & TSE_PCS_PARTNER_SPEED_MASK;
155		duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK;
156
157		if (speed == TSE_PCS_PARTNER_SPEED_10 &&
158		    duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
159			dev_dbg(pcs->dev,
160				"Adapter: Link Partner is Up - 10/Full\n");
161		else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
162			 duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
163			dev_dbg(pcs->dev,
164				"Adapter: Link Partner is Up - 100/Full\n");
165		else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
166			 duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
167			dev_dbg(pcs->dev,
168				"Adapter: Link Partner is Up - 1000/Full\n");
169		else if (speed == TSE_PCS_PARTNER_SPEED_10 &&
170			 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
171			dev_err(pcs->dev,
172				"Adapter does not support Half Duplex\n");
173		else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
174			 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
175			dev_err(pcs->dev,
176				"Adapter does not support Half Duplex\n");
177		else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
178			 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
179			dev_err(pcs->dev,
180				"Adapter does not support Half Duplex\n");
181		else
182			dev_err(pcs->dev,
183				"Adapter: Invalid Partner Speed and Duplex\n");
184
185		if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL &&
186		    (speed == TSE_PCS_PARTNER_SPEED_10 ||
187		     speed == TSE_PCS_PARTNER_SPEED_100 ||
188		     speed == TSE_PCS_PARTNER_SPEED_1000))
189			writew(SGMII_ADAPTER_ENABLE,
190			       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
191	} else {
192		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
193		val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
194		writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
195
196		tse_pcs_reset(tse_pcs_base, pcs);
197		mod_timer(&pcs->aneg_link_timer, jiffies +
198			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
199	}
200}
201
202static void aneg_link_timer_callback(struct timer_list *t)
203{
204	struct tse_pcs *pcs = from_timer(pcs, t, aneg_link_timer);
205
206	if (pcs->autoneg == AUTONEG_ENABLE)
207		auto_nego_timer_callback(pcs);
208	else if (pcs->autoneg == AUTONEG_DISABLE)
209		pcs_link_timer_callback(pcs);
210}
211
212void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
213			   unsigned int speed)
214{
215	void __iomem *tse_pcs_base = pcs->tse_pcs_base;
216	void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
217	u32 val;
218
219	writew(SGMII_ADAPTER_ENABLE,
220	       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
221
222	pcs->autoneg = phy_dev->autoneg;
223
224	if (phy_dev->autoneg == AUTONEG_ENABLE) {
225		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
226		val |= TSE_PCS_CONTROL_AN_EN_MASK;
227		writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
228
229		val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
230		val |= TSE_PCS_USE_SGMII_AN_MASK;
231		writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
232
233		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
234		val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
235
236		tse_pcs_reset(tse_pcs_base, pcs);
237
238		timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
239			    0);
240		mod_timer(&pcs->aneg_link_timer, jiffies +
241			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
242	} else if (phy_dev->autoneg == AUTONEG_DISABLE) {
243		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
244		val &= ~TSE_PCS_CONTROL_AN_EN_MASK;
245		writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
246
247		val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
248		val &= ~TSE_PCS_USE_SGMII_AN_MASK;
249		writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
250
251		val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
252		val &= ~TSE_PCS_SGMII_SPEED_MASK;
253
254		switch (speed) {
255		case 1000:
256			val |= TSE_PCS_SGMII_SPEED_1000;
257			break;
258		case 100:
259			val |= TSE_PCS_SGMII_SPEED_100;
260			break;
261		case 10:
262			val |= TSE_PCS_SGMII_SPEED_10;
263			break;
264		default:
265			return;
266		}
267		writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
268
269		tse_pcs_reset(tse_pcs_base, pcs);
270
271		timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
272			    0);
273		mod_timer(&pcs->aneg_link_timer, jiffies +
274			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
275	}
276}