Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * SGMI module initialisation
0004  *
0005  * Copyright (C) 2014 Texas Instruments Incorporated
0006  * Authors: Sandeep Nair <sandeep_n@ti.com>
0007  *      Sandeep Paulraj <s-paulraj@ti.com>
0008  *      Wingman Kwok <w-kwok2@ti.com>
0009  *
0010  */
0011 
0012 #include "netcp.h"
0013 
0014 #define SGMII_SRESET_RESET      BIT(0)
0015 #define SGMII_SRESET_RTRESET        BIT(1)
0016 
0017 #define SGMII_REG_STATUS_LOCK       BIT(4)
0018 #define SGMII_REG_STATUS_LINK       BIT(0)
0019 #define SGMII_REG_STATUS_AUTONEG    BIT(2)
0020 #define SGMII_REG_CONTROL_AUTONEG   BIT(0)
0021 
0022 #define SGMII23_OFFSET(x)   ((x - 2) * 0x100)
0023 #define SGMII_OFFSET(x)     ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x)))
0024 
0025 /* SGMII registers */
0026 #define SGMII_SRESET_REG(x)   (SGMII_OFFSET(x) + 0x004)
0027 #define SGMII_CTL_REG(x)      (SGMII_OFFSET(x) + 0x010)
0028 #define SGMII_STATUS_REG(x)   (SGMII_OFFSET(x) + 0x014)
0029 #define SGMII_MRADV_REG(x)    (SGMII_OFFSET(x) + 0x018)
0030 
0031 static void sgmii_write_reg(void __iomem *base, int reg, u32 val)
0032 {
0033     writel(val, base + reg);
0034 }
0035 
0036 static u32 sgmii_read_reg(void __iomem *base, int reg)
0037 {
0038     return readl(base + reg);
0039 }
0040 
0041 static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val)
0042 {
0043     writel((readl(base + reg) | val), base + reg);
0044 }
0045 
0046 /* port is 0 based */
0047 int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port)
0048 {
0049     /* Soft reset */
0050     sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port),
0051                 SGMII_SRESET_RESET);
0052 
0053     while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) &
0054         SGMII_SRESET_RESET) != 0x0)
0055         ;
0056 
0057     return 0;
0058 }
0059 
0060 /* port is 0 based */
0061 bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set)
0062 {
0063     u32 reg;
0064     bool oldval;
0065 
0066     /* Initiate a soft reset */
0067     reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port));
0068     oldval = (reg & SGMII_SRESET_RTRESET) != 0x0;
0069     if (set)
0070         reg |= SGMII_SRESET_RTRESET;
0071     else
0072         reg &= ~SGMII_SRESET_RTRESET;
0073     sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg);
0074     wmb();
0075 
0076     return oldval;
0077 }
0078 
0079 int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port)
0080 {
0081     u32 status = 0, link = 0;
0082 
0083     status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
0084     if ((status & SGMII_REG_STATUS_LINK) != 0)
0085         link = 1;
0086     return link;
0087 }
0088 
0089 int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface)
0090 {
0091     unsigned int i, status, mask;
0092     u32 mr_adv_ability;
0093     u32 control;
0094 
0095     switch (interface) {
0096     case SGMII_LINK_MAC_MAC_AUTONEG:
0097         mr_adv_ability  = 0x9801;
0098         control     = 0x21;
0099         break;
0100 
0101     case SGMII_LINK_MAC_PHY:
0102     case SGMII_LINK_MAC_PHY_NO_MDIO:
0103         mr_adv_ability  = 1;
0104         control     = 1;
0105         break;
0106 
0107     case SGMII_LINK_MAC_MAC_FORCED:
0108         mr_adv_ability  = 0x9801;
0109         control     = 0x20;
0110         break;
0111 
0112     case SGMII_LINK_MAC_FIBER:
0113         mr_adv_ability  = 0x20;
0114         control     = 0x1;
0115         break;
0116 
0117     default:
0118         WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface);
0119         return -EINVAL;
0120     }
0121 
0122     sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0);
0123 
0124     /* Wait for the SerDes pll to lock */
0125     for (i = 0; i < 1000; i++)  {
0126         usleep_range(1000, 2000);
0127         status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
0128         if ((status & SGMII_REG_STATUS_LOCK) != 0)
0129             break;
0130     }
0131 
0132     if ((status & SGMII_REG_STATUS_LOCK) == 0)
0133         pr_err("serdes PLL not locked\n");
0134 
0135     sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability);
0136     sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control);
0137 
0138     mask = SGMII_REG_STATUS_LINK;
0139     if (control & SGMII_REG_CONTROL_AUTONEG)
0140         mask |= SGMII_REG_STATUS_AUTONEG;
0141 
0142     for (i = 0; i < 1000; i++)  {
0143         usleep_range(200, 500);
0144         status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
0145         if ((status & mask) == mask)
0146             break;
0147     }
0148 
0149     return 0;
0150 }