Merge branch 'for-linus' into for-next
[linux-2.6-microblaze.git] / drivers / net / ethernet / freescale / enetc / enetc_mdio.c
1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2019 NXP */
3
4 #include <linux/mdio.h>
5 #include <linux/of_mdio.h>
6 #include <linux/iopoll.h>
7 #include <linux/of.h>
8
9 #include "enetc_pf.h"
10
11 struct enetc_mdio_regs {
12         u32     mdio_cfg;       /* MDIO configuration and status */
13         u32     mdio_ctl;       /* MDIO control */
14         u32     mdio_data;      /* MDIO data */
15         u32     mdio_addr;      /* MDIO address */
16 };
17
18 #define bus_to_enetc_regs(bus)  (struct enetc_mdio_regs __iomem *)((bus)->priv)
19
20 #define ENETC_MDIO_REG_OFFSET   0x1c00
21 #define ENETC_MDC_DIV           258
22
23 #define MDIO_CFG_CLKDIV(x)      ((((x) >> 1) & 0xff) << 8)
24 #define MDIO_CFG_BSY            BIT(0)
25 #define MDIO_CFG_RD_ER          BIT(1)
26 #define MDIO_CFG_ENC45          BIT(6)
27  /* external MDIO only - driven on neg MDC edge */
28 #define MDIO_CFG_NEG            BIT(23)
29
30 #define MDIO_CTL_DEV_ADDR(x)    ((x) & 0x1f)
31 #define MDIO_CTL_PORT_ADDR(x)   (((x) & 0x1f) << 5)
32 #define MDIO_CTL_READ           BIT(15)
33 #define MDIO_DATA(x)            ((x) & 0xffff)
34
35 #define TIMEOUT 1000
36 static int enetc_mdio_wait_complete(struct enetc_mdio_regs __iomem *regs)
37 {
38         u32 val;
39
40         return readx_poll_timeout(enetc_rd_reg, &regs->mdio_cfg, val,
41                                   !(val & MDIO_CFG_BSY), 10, 10 * TIMEOUT);
42 }
43
44 static int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
45                             u16 value)
46 {
47         struct enetc_mdio_regs __iomem *regs = bus_to_enetc_regs(bus);
48         u32 mdio_ctl, mdio_cfg;
49         u16 dev_addr;
50         int ret;
51
52         mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
53         if (regnum & MII_ADDR_C45) {
54                 dev_addr = (regnum >> 16) & 0x1f;
55                 mdio_cfg |= MDIO_CFG_ENC45;
56         } else {
57                 /* clause 22 (ie 1G) */
58                 dev_addr = regnum & 0x1f;
59                 mdio_cfg &= ~MDIO_CFG_ENC45;
60         }
61
62         enetc_wr_reg(&regs->mdio_cfg, mdio_cfg);
63
64         ret = enetc_mdio_wait_complete(regs);
65         if (ret)
66                 return ret;
67
68         /* set port and dev addr */
69         mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
70         enetc_wr_reg(&regs->mdio_ctl, mdio_ctl);
71
72         /* set the register address */
73         if (regnum & MII_ADDR_C45) {
74                 enetc_wr_reg(&regs->mdio_addr, regnum & 0xffff);
75
76                 ret = enetc_mdio_wait_complete(regs);
77                 if (ret)
78                         return ret;
79         }
80
81         /* write the value */
82         enetc_wr_reg(&regs->mdio_data, MDIO_DATA(value));
83
84         ret = enetc_mdio_wait_complete(regs);
85         if (ret)
86                 return ret;
87
88         return 0;
89 }
90
91 static int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
92 {
93         struct enetc_mdio_regs __iomem *regs = bus_to_enetc_regs(bus);
94         u32 mdio_ctl, mdio_cfg;
95         u16 dev_addr, value;
96         int ret;
97
98         mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
99         if (regnum & MII_ADDR_C45) {
100                 dev_addr = (regnum >> 16) & 0x1f;
101                 mdio_cfg |= MDIO_CFG_ENC45;
102         } else {
103                 dev_addr = regnum & 0x1f;
104                 mdio_cfg &= ~MDIO_CFG_ENC45;
105         }
106
107         enetc_wr_reg(&regs->mdio_cfg, mdio_cfg);
108
109         ret = enetc_mdio_wait_complete(regs);
110         if (ret)
111                 return ret;
112
113         /* set port and device addr */
114         mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
115         enetc_wr_reg(&regs->mdio_ctl, mdio_ctl);
116
117         /* set the register address */
118         if (regnum & MII_ADDR_C45) {
119                 enetc_wr_reg(&regs->mdio_addr, regnum & 0xffff);
120
121                 ret = enetc_mdio_wait_complete(regs);
122                 if (ret)
123                         return ret;
124         }
125
126         /* initiate the read */
127         enetc_wr_reg(&regs->mdio_ctl, mdio_ctl | MDIO_CTL_READ);
128
129         ret = enetc_mdio_wait_complete(regs);
130         if (ret)
131                 return ret;
132
133         /* return all Fs if nothing was there */
134         if (enetc_rd_reg(&regs->mdio_cfg) & MDIO_CFG_RD_ER) {
135                 dev_dbg(&bus->dev,
136                         "Error while reading PHY%d reg at %d.%hhu\n",
137                         phy_id, dev_addr, regnum);
138                 return 0xffff;
139         }
140
141         value = enetc_rd_reg(&regs->mdio_data) & 0xffff;
142
143         return value;
144 }
145
146 int enetc_mdio_probe(struct enetc_pf *pf)
147 {
148         struct device *dev = &pf->si->pdev->dev;
149         struct enetc_mdio_regs __iomem *regs;
150         struct device_node *np;
151         struct mii_bus *bus;
152         int ret;
153
154         bus = mdiobus_alloc_size(sizeof(regs));
155         if (!bus)
156                 return -ENOMEM;
157
158         bus->name = "Freescale ENETC MDIO Bus";
159         bus->read = enetc_mdio_read;
160         bus->write = enetc_mdio_write;
161         bus->parent = dev;
162         snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
163
164         /* store the enetc mdio base address for this bus */
165         regs = pf->si->hw.port + ENETC_MDIO_REG_OFFSET;
166         bus->priv = regs;
167
168         np = of_get_child_by_name(dev->of_node, "mdio");
169         if (!np) {
170                 dev_err(dev, "MDIO node missing\n");
171                 ret = -EINVAL;
172                 goto err_registration;
173         }
174
175         ret = of_mdiobus_register(bus, np);
176         if (ret) {
177                 of_node_put(np);
178                 dev_err(dev, "cannot register MDIO bus\n");
179                 goto err_registration;
180         }
181
182         of_node_put(np);
183         pf->mdio = bus;
184
185         return 0;
186
187 err_registration:
188         mdiobus_free(bus);
189
190         return ret;
191 }
192
193 void enetc_mdio_remove(struct enetc_pf *pf)
194 {
195         if (pf->mdio) {
196                 mdiobus_unregister(pf->mdio);
197                 mdiobus_free(pf->mdio);
198         }
199 }