netcp_sgmii.c (3507B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * SGMI module initialisation 4 * 5 * Copyright (C) 2014 Texas Instruments Incorporated 6 * Authors: Sandeep Nair <sandeep_n@ti.com> 7 * Sandeep Paulraj <s-paulraj@ti.com> 8 * Wingman Kwok <w-kwok2@ti.com> 9 * 10 */ 11 12#include "netcp.h" 13 14#define SGMII_SRESET_RESET BIT(0) 15#define SGMII_SRESET_RTRESET BIT(1) 16 17#define SGMII_REG_STATUS_LOCK BIT(4) 18#define SGMII_REG_STATUS_LINK BIT(0) 19#define SGMII_REG_STATUS_AUTONEG BIT(2) 20#define SGMII_REG_CONTROL_AUTONEG BIT(0) 21 22#define SGMII23_OFFSET(x) ((x - 2) * 0x100) 23#define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x))) 24 25/* SGMII registers */ 26#define SGMII_SRESET_REG(x) (SGMII_OFFSET(x) + 0x004) 27#define SGMII_CTL_REG(x) (SGMII_OFFSET(x) + 0x010) 28#define SGMII_STATUS_REG(x) (SGMII_OFFSET(x) + 0x014) 29#define SGMII_MRADV_REG(x) (SGMII_OFFSET(x) + 0x018) 30 31static void sgmii_write_reg(void __iomem *base, int reg, u32 val) 32{ 33 writel(val, base + reg); 34} 35 36static u32 sgmii_read_reg(void __iomem *base, int reg) 37{ 38 return readl(base + reg); 39} 40 41static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val) 42{ 43 writel((readl(base + reg) | val), base + reg); 44} 45 46/* port is 0 based */ 47int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port) 48{ 49 /* Soft reset */ 50 sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 51 SGMII_SRESET_RESET); 52 53 while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) & 54 SGMII_SRESET_RESET) != 0x0) 55 ; 56 57 return 0; 58} 59 60/* port is 0 based */ 61bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set) 62{ 63 u32 reg; 64 bool oldval; 65 66 /* Initiate a soft reset */ 67 reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)); 68 oldval = (reg & SGMII_SRESET_RTRESET) != 0x0; 69 if (set) 70 reg |= SGMII_SRESET_RTRESET; 71 else 72 reg &= ~SGMII_SRESET_RTRESET; 73 sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg); 74 wmb(); 75 76 return oldval; 77} 78 79int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port) 80{ 81 u32 status = 0, link = 0; 82 83 status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); 84 if ((status & SGMII_REG_STATUS_LINK) != 0) 85 link = 1; 86 return link; 87} 88 89int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface) 90{ 91 unsigned int i, status, mask; 92 u32 mr_adv_ability; 93 u32 control; 94 95 switch (interface) { 96 case SGMII_LINK_MAC_MAC_AUTONEG: 97 mr_adv_ability = 0x9801; 98 control = 0x21; 99 break; 100 101 case SGMII_LINK_MAC_PHY: 102 case SGMII_LINK_MAC_PHY_NO_MDIO: 103 mr_adv_ability = 1; 104 control = 1; 105 break; 106 107 case SGMII_LINK_MAC_MAC_FORCED: 108 mr_adv_ability = 0x9801; 109 control = 0x20; 110 break; 111 112 case SGMII_LINK_MAC_FIBER: 113 mr_adv_ability = 0x20; 114 control = 0x1; 115 break; 116 117 default: 118 WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface); 119 return -EINVAL; 120 } 121 122 sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0); 123 124 /* Wait for the SerDes pll to lock */ 125 for (i = 0; i < 1000; i++) { 126 usleep_range(1000, 2000); 127 status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); 128 if ((status & SGMII_REG_STATUS_LOCK) != 0) 129 break; 130 } 131 132 if ((status & SGMII_REG_STATUS_LOCK) == 0) 133 pr_err("serdes PLL not locked\n"); 134 135 sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability); 136 sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control); 137 138 mask = SGMII_REG_STATUS_LINK; 139 if (control & SGMII_REG_CONTROL_AUTONEG) 140 mask |= SGMII_REG_STATUS_AUTONEG; 141 142 for (i = 0; i < 1000; i++) { 143 usleep_range(200, 500); 144 status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); 145 if ((status & mask) == mask) 146 break; 147 } 148 149 return 0; 150}