Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / ethernet / ti / netcp_sgmii.c
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 }