0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/clk.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_mdio.h>
0015 #include <linux/jiffies.h>
0016 #include <linux/iopoll.h>
0017
0018 #include "xilinx_axienet.h"
0019
0020 #define MAX_MDIO_FREQ 2500000
0021 #define DEFAULT_HOST_CLOCK 150000000
0022
0023
0024 static int axienet_mdio_wait_until_ready(struct axienet_local *lp)
0025 {
0026 u32 val;
0027
0028 return readx_poll_timeout(axinet_ior_read_mcr, lp,
0029 val, val & XAE_MDIO_MCR_READY_MASK,
0030 1, 20000);
0031 }
0032
0033
0034 static void axienet_mdio_mdc_enable(struct axienet_local *lp)
0035 {
0036 axienet_iow(lp, XAE_MDIO_MC_OFFSET,
0037 ((u32)lp->mii_clk_div | XAE_MDIO_MC_MDIOEN_MASK));
0038 }
0039
0040
0041 static void axienet_mdio_mdc_disable(struct axienet_local *lp)
0042 {
0043 u32 mc_reg;
0044
0045 mc_reg = axienet_ior(lp, XAE_MDIO_MC_OFFSET);
0046 axienet_iow(lp, XAE_MDIO_MC_OFFSET,
0047 (mc_reg & ~XAE_MDIO_MC_MDIOEN_MASK));
0048 }
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg)
0063 {
0064 u32 rc;
0065 int ret;
0066 struct axienet_local *lp = bus->priv;
0067
0068 axienet_mdio_mdc_enable(lp);
0069
0070 ret = axienet_mdio_wait_until_ready(lp);
0071 if (ret < 0) {
0072 axienet_mdio_mdc_disable(lp);
0073 return ret;
0074 }
0075
0076 axienet_iow(lp, XAE_MDIO_MCR_OFFSET,
0077 (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) &
0078 XAE_MDIO_MCR_PHYAD_MASK) |
0079 ((reg << XAE_MDIO_MCR_REGAD_SHIFT) &
0080 XAE_MDIO_MCR_REGAD_MASK) |
0081 XAE_MDIO_MCR_INITIATE_MASK |
0082 XAE_MDIO_MCR_OP_READ_MASK));
0083
0084 ret = axienet_mdio_wait_until_ready(lp);
0085 if (ret < 0) {
0086 axienet_mdio_mdc_disable(lp);
0087 return ret;
0088 }
0089
0090 rc = axienet_ior(lp, XAE_MDIO_MRD_OFFSET) & 0x0000FFFF;
0091
0092 dev_dbg(lp->dev, "axienet_mdio_read(phy_id=%i, reg=%x) == %x\n",
0093 phy_id, reg, rc);
0094
0095 axienet_mdio_mdc_disable(lp);
0096 return rc;
0097 }
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
0113 u16 val)
0114 {
0115 int ret;
0116 struct axienet_local *lp = bus->priv;
0117
0118 dev_dbg(lp->dev, "axienet_mdio_write(phy_id=%i, reg=%x, val=%x)\n",
0119 phy_id, reg, val);
0120
0121 axienet_mdio_mdc_enable(lp);
0122
0123 ret = axienet_mdio_wait_until_ready(lp);
0124 if (ret < 0) {
0125 axienet_mdio_mdc_disable(lp);
0126 return ret;
0127 }
0128
0129 axienet_iow(lp, XAE_MDIO_MWD_OFFSET, (u32) val);
0130 axienet_iow(lp, XAE_MDIO_MCR_OFFSET,
0131 (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) &
0132 XAE_MDIO_MCR_PHYAD_MASK) |
0133 ((reg << XAE_MDIO_MCR_REGAD_SHIFT) &
0134 XAE_MDIO_MCR_REGAD_MASK) |
0135 XAE_MDIO_MCR_INITIATE_MASK |
0136 XAE_MDIO_MCR_OP_WRITE_MASK));
0137
0138 ret = axienet_mdio_wait_until_ready(lp);
0139 if (ret < 0) {
0140 axienet_mdio_mdc_disable(lp);
0141 return ret;
0142 }
0143 axienet_mdio_mdc_disable(lp);
0144 return 0;
0145 }
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 int axienet_mdio_enable(struct axienet_local *lp)
0157 {
0158 u32 host_clock;
0159
0160 lp->mii_clk_div = 0;
0161
0162 if (lp->axi_clk) {
0163 host_clock = clk_get_rate(lp->axi_clk);
0164 } else {
0165 struct device_node *np1;
0166
0167
0168
0169
0170 np1 = of_find_node_by_name(NULL, "cpu");
0171 if (!np1) {
0172 netdev_warn(lp->ndev, "Could not find CPU device node.\n");
0173 host_clock = DEFAULT_HOST_CLOCK;
0174 } else {
0175 int ret = of_property_read_u32(np1, "clock-frequency",
0176 &host_clock);
0177 if (ret) {
0178 netdev_warn(lp->ndev, "CPU clock-frequency property not found.\n");
0179 host_clock = DEFAULT_HOST_CLOCK;
0180 }
0181 of_node_put(np1);
0182 }
0183 netdev_info(lp->ndev, "Setting assumed host clock to %u\n",
0184 host_clock);
0185 }
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212 lp->mii_clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1;
0213
0214
0215
0216
0217 if (host_clock % (MAX_MDIO_FREQ * 2))
0218 lp->mii_clk_div++;
0219
0220 netdev_dbg(lp->ndev,
0221 "Setting MDIO clock divisor to %u/%u Hz host clock.\n",
0222 lp->mii_clk_div, host_clock);
0223
0224 axienet_iow(lp, XAE_MDIO_MC_OFFSET, lp->mii_clk_div | XAE_MDIO_MC_MDIOEN_MASK);
0225
0226 return axienet_mdio_wait_until_ready(lp);
0227 }
0228
0229
0230
0231
0232
0233
0234
0235 void axienet_mdio_disable(struct axienet_local *lp)
0236 {
0237 axienet_iow(lp, XAE_MDIO_MC_OFFSET, 0);
0238 }
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 int axienet_mdio_setup(struct axienet_local *lp)
0251 {
0252 struct device_node *mdio_node;
0253 struct mii_bus *bus;
0254 int ret;
0255
0256 ret = axienet_mdio_enable(lp);
0257 if (ret < 0)
0258 return ret;
0259
0260 bus = mdiobus_alloc();
0261 if (!bus)
0262 return -ENOMEM;
0263
0264 snprintf(bus->id, MII_BUS_ID_SIZE, "axienet-%.8llx",
0265 (unsigned long long)lp->regs_start);
0266
0267 bus->priv = lp;
0268 bus->name = "Xilinx Axi Ethernet MDIO";
0269 bus->read = axienet_mdio_read;
0270 bus->write = axienet_mdio_write;
0271 bus->parent = lp->dev;
0272 lp->mii_bus = bus;
0273
0274 mdio_node = of_get_child_by_name(lp->dev->of_node, "mdio");
0275 ret = of_mdiobus_register(bus, mdio_node);
0276 of_node_put(mdio_node);
0277 if (ret) {
0278 mdiobus_free(bus);
0279 lp->mii_bus = NULL;
0280 return ret;
0281 }
0282 axienet_mdio_mdc_disable(lp);
0283 return 0;
0284 }
0285
0286
0287
0288
0289
0290
0291
0292 void axienet_mdio_teardown(struct axienet_local *lp)
0293 {
0294 mdiobus_unregister(lp->mii_bus);
0295 mdiobus_free(lp->mii_bus);
0296 lp->mii_bus = NULL;
0297 }