mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
3.4 KiB
150 lines
3.4 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* SGMI module initialisation |
|
* |
|
* Copyright (C) 2014 Texas Instruments Incorporated |
|
* Authors: Sandeep Nair <[email protected]> |
|
* Sandeep Paulraj <[email protected]> |
|
* Wingman Kwok <[email protected]> |
|
* |
|
*/ |
|
|
|
#include "netcp.h" |
|
|
|
#define SGMII_SRESET_RESET BIT(0) |
|
#define SGMII_SRESET_RTRESET BIT(1) |
|
|
|
#define SGMII_REG_STATUS_LOCK BIT(4) |
|
#define SGMII_REG_STATUS_LINK BIT(0) |
|
#define SGMII_REG_STATUS_AUTONEG BIT(2) |
|
#define SGMII_REG_CONTROL_AUTONEG BIT(0) |
|
|
|
#define SGMII23_OFFSET(x) ((x - 2) * 0x100) |
|
#define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x))) |
|
|
|
/* SGMII registers */ |
|
#define SGMII_SRESET_REG(x) (SGMII_OFFSET(x) + 0x004) |
|
#define SGMII_CTL_REG(x) (SGMII_OFFSET(x) + 0x010) |
|
#define SGMII_STATUS_REG(x) (SGMII_OFFSET(x) + 0x014) |
|
#define SGMII_MRADV_REG(x) (SGMII_OFFSET(x) + 0x018) |
|
|
|
static void sgmii_write_reg(void __iomem *base, int reg, u32 val) |
|
{ |
|
writel(val, base + reg); |
|
} |
|
|
|
static u32 sgmii_read_reg(void __iomem *base, int reg) |
|
{ |
|
return readl(base + reg); |
|
} |
|
|
|
static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val) |
|
{ |
|
writel((readl(base + reg) | val), base + reg); |
|
} |
|
|
|
/* port is 0 based */ |
|
int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port) |
|
{ |
|
/* Soft reset */ |
|
sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), |
|
SGMII_SRESET_RESET); |
|
|
|
while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) & |
|
SGMII_SRESET_RESET) != 0x0) |
|
; |
|
|
|
return 0; |
|
} |
|
|
|
/* port is 0 based */ |
|
bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set) |
|
{ |
|
u32 reg; |
|
bool oldval; |
|
|
|
/* Initiate a soft reset */ |
|
reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)); |
|
oldval = (reg & SGMII_SRESET_RTRESET) != 0x0; |
|
if (set) |
|
reg |= SGMII_SRESET_RTRESET; |
|
else |
|
reg &= ~SGMII_SRESET_RTRESET; |
|
sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg); |
|
wmb(); |
|
|
|
return oldval; |
|
} |
|
|
|
int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port) |
|
{ |
|
u32 status = 0, link = 0; |
|
|
|
status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); |
|
if ((status & SGMII_REG_STATUS_LINK) != 0) |
|
link = 1; |
|
return link; |
|
} |
|
|
|
int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface) |
|
{ |
|
unsigned int i, status, mask; |
|
u32 mr_adv_ability; |
|
u32 control; |
|
|
|
switch (interface) { |
|
case SGMII_LINK_MAC_MAC_AUTONEG: |
|
mr_adv_ability = 0x9801; |
|
control = 0x21; |
|
break; |
|
|
|
case SGMII_LINK_MAC_PHY: |
|
case SGMII_LINK_MAC_PHY_NO_MDIO: |
|
mr_adv_ability = 1; |
|
control = 1; |
|
break; |
|
|
|
case SGMII_LINK_MAC_MAC_FORCED: |
|
mr_adv_ability = 0x9801; |
|
control = 0x20; |
|
break; |
|
|
|
case SGMII_LINK_MAC_FIBER: |
|
mr_adv_ability = 0x20; |
|
control = 0x1; |
|
break; |
|
|
|
default: |
|
WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface); |
|
return -EINVAL; |
|
} |
|
|
|
sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0); |
|
|
|
/* Wait for the SerDes pll to lock */ |
|
for (i = 0; i < 1000; i++) { |
|
usleep_range(1000, 2000); |
|
status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); |
|
if ((status & SGMII_REG_STATUS_LOCK) != 0) |
|
break; |
|
} |
|
|
|
if ((status & SGMII_REG_STATUS_LOCK) == 0) |
|
pr_err("serdes PLL not locked\n"); |
|
|
|
sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability); |
|
sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control); |
|
|
|
mask = SGMII_REG_STATUS_LINK; |
|
if (control & SGMII_REG_CONTROL_AUTONEG) |
|
mask |= SGMII_REG_STATUS_AUTONEG; |
|
|
|
for (i = 0; i < 1000; i++) { |
|
usleep_range(200, 500); |
|
status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); |
|
if ((status & mask) == mask) |
|
break; |
|
} |
|
|
|
return 0; |
|
}
|
|
|