Skip to content

Commit 02b2a6f

Browse files
Jiawen Wudavem330
authored andcommitted
net: txgbe: support copper NIC with external PHY
Wangxun SP chip supports to connect with external PHY (marvell 88x3310), which links to 10GBASE-T/1000BASE-T/100BASE-T. Add the identification of media types from subsystem device IDs. For sp_media_copper, register mdio bus for the external PHY. Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent a4414dd commit 02b2a6f

File tree

5 files changed

+221
-22
lines changed

5 files changed

+221
-22
lines changed

drivers/net/ethernet/wangxun/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ config TXGBE
4141
tristate "Wangxun(R) 10GbE PCI Express adapters support"
4242
depends on PCI
4343
depends on COMMON_CLK
44+
select MARVELL_10G_PHY
4445
select REGMAP
4546
select I2C
4647
select I2C_DESIGNWARE_PLATFORM

drivers/net/ethernet/wangxun/libwx/wx_type.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,24 @@
233233
#define WX_MAC_WDG_TIMEOUT 0x1100C
234234
#define WX_MAC_RX_FLOW_CTRL 0x11090
235235
#define WX_MAC_RX_FLOW_CTRL_RFE BIT(0) /* receive fc enable */
236+
/* MDIO Registers */
237+
#define WX_MSCA 0x11200
238+
#define WX_MSCA_RA(v) FIELD_PREP(U16_MAX, v)
239+
#define WX_MSCA_PA(v) FIELD_PREP(GENMASK(20, 16), v)
240+
#define WX_MSCA_DA(v) FIELD_PREP(GENMASK(25, 21), v)
241+
#define WX_MSCC 0x11204
242+
#define WX_MSCC_CMD(v) FIELD_PREP(GENMASK(17, 16), v)
243+
244+
enum WX_MSCA_CMD_value {
245+
WX_MSCA_CMD_RSV = 0,
246+
WX_MSCA_CMD_WRITE,
247+
WX_MSCA_CMD_POST_READ,
248+
WX_MSCA_CMD_READ,
249+
};
250+
251+
#define WX_MSCC_SADDR BIT(18)
252+
#define WX_MSCC_BUSY BIT(22)
253+
#define WX_MDIO_CLK(v) FIELD_PREP(GENMASK(21, 19), v)
236254
#define WX_MMC_CONTROL 0x11800
237255
#define WX_MMC_CONTROL_RSTONRD BIT(2) /* reset on read */
238256

@@ -582,6 +600,13 @@ enum wx_mac_type {
582600
wx_mac_em
583601
};
584602

603+
enum sp_media_type {
604+
sp_media_unknown = 0,
605+
sp_media_fiber,
606+
sp_media_copper,
607+
sp_media_backplane
608+
};
609+
585610
enum em_mac_type {
586611
em_mac_type_unknown = 0,
587612
em_mac_type_mdi,
@@ -829,6 +854,7 @@ struct wx {
829854
struct wx_bus_info bus;
830855
struct wx_mac_info mac;
831856
enum em_mac_type mac_type;
857+
enum sp_media_type media_type;
832858
struct wx_eeprom_info eeprom;
833859
struct wx_addr_filter_info addr_ctrl;
834860
struct wx_mac_addr *mac_table;

drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,17 +285,20 @@ static void txgbe_reset_misc(struct wx *wx)
285285
int txgbe_reset_hw(struct wx *wx)
286286
{
287287
int status;
288-
u32 val;
289288

290289
/* Call adapter stop to disable tx/rx and clear interrupts */
291290
status = wx_stop_adapter(wx);
292291
if (status != 0)
293292
return status;
294293

295-
val = WX_MIS_RST_LAN_RST(wx->bus.func);
296-
wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
297-
WX_WRITE_FLUSH(wx);
298-
usleep_range(10, 100);
294+
if (wx->media_type != sp_media_copper) {
295+
u32 val;
296+
297+
val = WX_MIS_RST_LAN_RST(wx->bus.func);
298+
wr32(wx, WX_MIS_RST, val | rd32(wx, WX_MIS_RST));
299+
WX_WRITE_FLUSH(wx);
300+
usleep_range(10, 100);
301+
}
299302

300303
status = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_LAN_SW_RST(wx->bus.func));
301304
if (status != 0)

drivers/net/ethernet/wangxun/txgbe/txgbe_main.c

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,49 @@ static void txgbe_down(struct wx *wx)
300300
wx_clean_all_rx_rings(wx);
301301
}
302302

303+
/**
304+
* txgbe_init_type_code - Initialize the shared code
305+
* @wx: pointer to hardware structure
306+
**/
307+
static void txgbe_init_type_code(struct wx *wx)
308+
{
309+
u8 device_type = wx->subsystem_device_id & 0xF0;
310+
311+
switch (wx->device_id) {
312+
case TXGBE_DEV_ID_SP1000:
313+
case TXGBE_DEV_ID_WX1820:
314+
wx->mac.type = wx_mac_sp;
315+
break;
316+
default:
317+
wx->mac.type = wx_mac_unknown;
318+
break;
319+
}
320+
321+
switch (device_type) {
322+
case TXGBE_ID_SFP:
323+
wx->media_type = sp_media_fiber;
324+
break;
325+
case TXGBE_ID_XAUI:
326+
case TXGBE_ID_SGMII:
327+
wx->media_type = sp_media_copper;
328+
break;
329+
case TXGBE_ID_KR_KX_KX4:
330+
case TXGBE_ID_MAC_XAUI:
331+
case TXGBE_ID_MAC_SGMII:
332+
wx->media_type = sp_media_backplane;
333+
break;
334+
case TXGBE_ID_SFI_XAUI:
335+
if (wx->bus.func == 0)
336+
wx->media_type = sp_media_fiber;
337+
else
338+
wx->media_type = sp_media_copper;
339+
break;
340+
default:
341+
wx->media_type = sp_media_unknown;
342+
break;
343+
}
344+
}
345+
303346
/**
304347
* txgbe_sw_init - Initialize general software structures (struct wx)
305348
* @wx: board private structure to initialize
@@ -324,15 +367,7 @@ static int txgbe_sw_init(struct wx *wx)
324367
return err;
325368
}
326369

327-
switch (wx->device_id) {
328-
case TXGBE_DEV_ID_SP1000:
329-
case TXGBE_DEV_ID_WX1820:
330-
wx->mac.type = wx_mac_sp;
331-
break;
332-
default:
333-
wx->mac.type = wx_mac_unknown;
334-
break;
335-
}
370+
txgbe_init_type_code(wx);
336371

337372
/* Set common capability flags and settings */
338373
wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;

drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c

Lines changed: 142 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi
161161
{
162162
struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
163163

164-
return &txgbe->xpcs->pcs;
164+
if (interface == PHY_INTERFACE_MODE_10GBASER)
165+
return &txgbe->xpcs->pcs;
166+
167+
return NULL;
165168
}
166169

167170
static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
@@ -244,8 +247,8 @@ static const struct phylink_mac_ops txgbe_mac_ops = {
244247

245248
static int txgbe_phylink_init(struct txgbe *txgbe)
246249
{
250+
struct fwnode_handle *fwnode = NULL;
247251
struct phylink_config *config;
248-
struct fwnode_handle *fwnode;
249252
struct wx *wx = txgbe->wx;
250253
phy_interface_t phy_mode;
251254
struct phylink *phylink;
@@ -256,16 +259,34 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
256259

257260
config->dev = &wx->netdev->dev;
258261
config->type = PHYLINK_NETDEV;
259-
config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
260-
phy_mode = PHY_INTERFACE_MODE_10GBASER;
261-
__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
262-
__set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
263-
__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
264-
fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
262+
config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
263+
MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
264+
265+
if (wx->media_type == sp_media_copper) {
266+
phy_mode = PHY_INTERFACE_MODE_XAUI;
267+
__set_bit(PHY_INTERFACE_MODE_XAUI, config->supported_interfaces);
268+
} else {
269+
phy_mode = PHY_INTERFACE_MODE_10GBASER;
270+
fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]);
271+
__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
272+
__set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces);
273+
__set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces);
274+
}
275+
265276
phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops);
266277
if (IS_ERR(phylink))
267278
return PTR_ERR(phylink);
268279

280+
if (wx->phydev) {
281+
int ret;
282+
283+
ret = phylink_connect_phy(phylink, wx->phydev);
284+
if (ret) {
285+
phylink_destroy(phylink);
286+
return ret;
287+
}
288+
}
289+
269290
txgbe->phylink = phylink;
270291

271292
return 0;
@@ -626,10 +647,117 @@ static int txgbe_sfp_register(struct txgbe *txgbe)
626647
return 0;
627648
}
628649

650+
static int txgbe_phy_read(struct mii_bus *bus, int phy_addr,
651+
int devnum, int regnum)
652+
{
653+
struct wx *wx = bus->priv;
654+
u32 val, command;
655+
int ret;
656+
657+
/* setup and write the address cycle command */
658+
command = WX_MSCA_RA(regnum) |
659+
WX_MSCA_PA(phy_addr) |
660+
WX_MSCA_DA(devnum);
661+
wr32(wx, WX_MSCA, command);
662+
663+
command = WX_MSCC_CMD(WX_MSCA_CMD_READ) | WX_MSCC_BUSY;
664+
wr32(wx, WX_MSCC, command);
665+
666+
/* wait to complete */
667+
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
668+
100000, false, wx, WX_MSCC);
669+
if (ret) {
670+
wx_err(wx, "Mdio read c45 command did not complete.\n");
671+
return ret;
672+
}
673+
674+
return (u16)rd32(wx, WX_MSCC);
675+
}
676+
677+
static int txgbe_phy_write(struct mii_bus *bus, int phy_addr,
678+
int devnum, int regnum, u16 value)
679+
{
680+
struct wx *wx = bus->priv;
681+
int ret, command;
682+
u16 val;
683+
684+
/* setup and write the address cycle command */
685+
command = WX_MSCA_RA(regnum) |
686+
WX_MSCA_PA(phy_addr) |
687+
WX_MSCA_DA(devnum);
688+
wr32(wx, WX_MSCA, command);
689+
690+
command = value | WX_MSCC_CMD(WX_MSCA_CMD_WRITE) | WX_MSCC_BUSY;
691+
wr32(wx, WX_MSCC, command);
692+
693+
/* wait to complete */
694+
ret = read_poll_timeout(rd32, val, !(val & WX_MSCC_BUSY), 1000,
695+
100000, false, wx, WX_MSCC);
696+
if (ret)
697+
wx_err(wx, "Mdio write c45 command did not complete.\n");
698+
699+
return ret;
700+
}
701+
702+
static int txgbe_ext_phy_init(struct txgbe *txgbe)
703+
{
704+
struct phy_device *phydev;
705+
struct mii_bus *mii_bus;
706+
struct pci_dev *pdev;
707+
struct wx *wx;
708+
int ret = 0;
709+
710+
wx = txgbe->wx;
711+
pdev = wx->pdev;
712+
713+
mii_bus = devm_mdiobus_alloc(&pdev->dev);
714+
if (!mii_bus)
715+
return -ENOMEM;
716+
717+
mii_bus->name = "txgbe_mii_bus";
718+
mii_bus->read_c45 = &txgbe_phy_read;
719+
mii_bus->write_c45 = &txgbe_phy_write;
720+
mii_bus->parent = &pdev->dev;
721+
mii_bus->phy_mask = GENMASK(31, 1);
722+
mii_bus->priv = wx;
723+
snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe-%x",
724+
(pdev->bus->number << 8) | pdev->devfn);
725+
726+
ret = devm_mdiobus_register(&pdev->dev, mii_bus);
727+
if (ret) {
728+
wx_err(wx, "failed to register MDIO bus: %d\n", ret);
729+
return ret;
730+
}
731+
732+
phydev = phy_find_first(mii_bus);
733+
if (!phydev) {
734+
wx_err(wx, "no PHY found\n");
735+
return -ENODEV;
736+
}
737+
738+
phy_attached_info(phydev);
739+
740+
wx->link = 0;
741+
wx->speed = 0;
742+
wx->duplex = 0;
743+
wx->phydev = phydev;
744+
745+
ret = txgbe_phylink_init(txgbe);
746+
if (ret) {
747+
wx_err(wx, "failed to init phylink: %d\n", ret);
748+
return ret;
749+
}
750+
751+
return 0;
752+
}
753+
629754
int txgbe_init_phy(struct txgbe *txgbe)
630755
{
631756
int ret;
632757

758+
if (txgbe->wx->media_type == sp_media_copper)
759+
return txgbe_ext_phy_init(txgbe);
760+
633761
ret = txgbe_swnodes_register(txgbe);
634762
if (ret) {
635763
wx_err(txgbe->wx, "failed to register software nodes\n");
@@ -691,6 +819,12 @@ int txgbe_init_phy(struct txgbe *txgbe)
691819

692820
void txgbe_remove_phy(struct txgbe *txgbe)
693821
{
822+
if (txgbe->wx->media_type == sp_media_copper) {
823+
phylink_disconnect_phy(txgbe->phylink);
824+
phylink_destroy(txgbe->phylink);
825+
return;
826+
}
827+
694828
platform_device_unregister(txgbe->sfp_dev);
695829
platform_device_unregister(txgbe->i2c_dev);
696830
clkdev_drop(txgbe->clock);

0 commit comments

Comments
 (0)