Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

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