1 /* 2 * SGMI module initialisation 3 * 4 * Copyright (C) 2014 Texas Instruments Incorporated 5 * Authors: Sandeep Nair <sandeep_n@ti.com> 6 * Sandeep Paulraj <s-paulraj@ti.com> 7 * Wingman Kwok <w-kwok2@ti.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation version 2. 12 * 13 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 14 * kind, whether express or implied; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include "netcp.h" 20 21 #define SGMII_REG_STATUS_LOCK BIT(4) 22 #define SGMII_REG_STATUS_LINK BIT(0) 23 #define SGMII_REG_STATUS_AUTONEG BIT(2) 24 #define SGMII_REG_CONTROL_AUTONEG BIT(0) 25 26 #define SGMII23_OFFSET(x) ((x - 2) * 0x100) 27 #define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x))) 28 29 /* SGMII registers */ 30 #define SGMII_SRESET_REG(x) (SGMII_OFFSET(x) + 0x004) 31 #define SGMII_CTL_REG(x) (SGMII_OFFSET(x) + 0x010) 32 #define SGMII_STATUS_REG(x) (SGMII_OFFSET(x) + 0x014) 33 #define SGMII_MRADV_REG(x) (SGMII_OFFSET(x) + 0x018) 34 35 static void sgmii_write_reg(void __iomem *base, int reg, u32 val) 36 { 37 writel(val, base + reg); 38 } 39 40 static u32 sgmii_read_reg(void __iomem *base, int reg) 41 { 42 return readl(base + reg); 43 } 44 45 static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val) 46 { 47 writel((readl(base + reg) | val), base + reg); 48 } 49 50 /* port is 0 based */ 51 int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port) 52 { 53 /* Soft reset */ 54 sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 0x1); 55 while (sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) != 0x0) 56 ; 57 return 0; 58 } 59 60 int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port) 61 { 62 u32 status = 0, link = 0; 63 64 status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); 65 if ((status & SGMII_REG_STATUS_LINK) != 0) 66 link = 1; 67 return link; 68 } 69 70 int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface) 71 { 72 unsigned int i, status, mask; 73 u32 mr_adv_ability; 74 u32 control; 75 76 switch (interface) { 77 case SGMII_LINK_MAC_MAC_AUTONEG: 78 mr_adv_ability = 0x9801; 79 control = 0x21; 80 break; 81 82 case SGMII_LINK_MAC_PHY: 83 case SGMII_LINK_MAC_PHY_NO_MDIO: 84 mr_adv_ability = 1; 85 control = 1; 86 break; 87 88 case SGMII_LINK_MAC_MAC_FORCED: 89 mr_adv_ability = 0x9801; 90 control = 0x20; 91 break; 92 93 case SGMII_LINK_MAC_FIBER: 94 mr_adv_ability = 0x20; 95 control = 0x1; 96 break; 97 98 default: 99 WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface); 100 return -EINVAL; 101 } 102 103 sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0); 104 105 /* Wait for the SerDes pll to lock */ 106 for (i = 0; i < 1000; i++) { 107 usleep_range(1000, 2000); 108 status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); 109 if ((status & SGMII_REG_STATUS_LOCK) != 0) 110 break; 111 } 112 113 if ((status & SGMII_REG_STATUS_LOCK) == 0) 114 pr_err("serdes PLL not locked\n"); 115 116 sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability); 117 sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control); 118 119 mask = SGMII_REG_STATUS_LINK; 120 if (control & SGMII_REG_CONTROL_AUTONEG) 121 mask |= SGMII_REG_STATUS_AUTONEG; 122 123 for (i = 0; i < 1000; i++) { 124 usleep_range(200, 500); 125 status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port)); 126 if ((status & mask) == mask) 127 break; 128 } 129 130 return 0; 131 } 132