200 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2009-2016 Cavium, Inc.4 */5 6#include <linux/delay.h>7#include <linux/io.h>8#include <linux/module.h>9#include <linux/phy.h>10 11#include "mdio-cavium.h"12 13static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p,14 enum cavium_mdiobus_mode m)15{16 union cvmx_smix_clk smi_clk;17 18 if (m == p->mode)19 return;20 21 smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK);22 smi_clk.s.mode = (m == C45) ? 1 : 0;23 smi_clk.s.preamble = 1;24 oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK);25 p->mode = m;26}27 28static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,29 int phy_id, int devad, int regnum)30{31 union cvmx_smix_cmd smi_cmd;32 union cvmx_smix_wr_dat smi_wr;33 int timeout = 1000;34 35 cavium_mdiobus_set_mode(p, C45);36 37 smi_wr.u64 = 0;38 smi_wr.s.dat = regnum & 0xffff;39 oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);40 41 smi_cmd.u64 = 0;42 smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */43 smi_cmd.s.phy_adr = phy_id;44 smi_cmd.s.reg_adr = devad;45 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);46 47 do {48 /* Wait 1000 clocks so we don't saturate the RSL bus49 * doing reads.50 */51 __delay(1000);52 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);53 } while (smi_wr.s.pending && --timeout);54 55 if (timeout <= 0)56 return -EIO;57 return 0;58}59 60int cavium_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int regnum)61{62 struct cavium_mdiobus *p = bus->priv;63 union cvmx_smix_cmd smi_cmd;64 union cvmx_smix_rd_dat smi_rd;65 int timeout = 1000;66 67 cavium_mdiobus_set_mode(p, C22);68 69 smi_cmd.u64 = 0;70 smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */71 smi_cmd.s.phy_adr = phy_id;72 smi_cmd.s.reg_adr = regnum;73 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);74 75 do {76 /* Wait 1000 clocks so we don't saturate the RSL bus77 * doing reads.78 */79 __delay(1000);80 smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);81 } while (smi_rd.s.pending && --timeout);82 83 if (smi_rd.s.val)84 return smi_rd.s.dat;85 else86 return -EIO;87}88EXPORT_SYMBOL(cavium_mdiobus_read_c22);89 90int cavium_mdiobus_read_c45(struct mii_bus *bus, int phy_id, int devad,91 int regnum)92{93 struct cavium_mdiobus *p = bus->priv;94 union cvmx_smix_cmd smi_cmd;95 union cvmx_smix_rd_dat smi_rd;96 int timeout = 1000;97 int r;98 99 r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);100 if (r < 0)101 return r;102 103 smi_cmd.u64 = 0;104 smi_cmd.s.phy_op = 3; /* MDIO_CLAUSE_45_READ */105 smi_cmd.s.phy_adr = phy_id;106 smi_cmd.s.reg_adr = regnum;107 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);108 109 do {110 /* Wait 1000 clocks so we don't saturate the RSL bus111 * doing reads.112 */113 __delay(1000);114 smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);115 } while (smi_rd.s.pending && --timeout);116 117 if (smi_rd.s.val)118 return smi_rd.s.dat;119 else120 return -EIO;121}122EXPORT_SYMBOL(cavium_mdiobus_read_c45);123 124int cavium_mdiobus_write_c22(struct mii_bus *bus, int phy_id, int regnum,125 u16 val)126{127 struct cavium_mdiobus *p = bus->priv;128 union cvmx_smix_cmd smi_cmd;129 union cvmx_smix_wr_dat smi_wr;130 int timeout = 1000;131 132 cavium_mdiobus_set_mode(p, C22);133 134 smi_wr.u64 = 0;135 smi_wr.s.dat = val;136 oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);137 138 smi_cmd.u64 = 0;139 smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */140 smi_cmd.s.phy_adr = phy_id;141 smi_cmd.s.reg_adr = regnum;142 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);143 144 do {145 /* Wait 1000 clocks so we don't saturate the RSL bus146 * doing reads.147 */148 __delay(1000);149 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);150 } while (smi_wr.s.pending && --timeout);151 152 if (timeout <= 0)153 return -EIO;154 155 return 0;156}157EXPORT_SYMBOL(cavium_mdiobus_write_c22);158 159int cavium_mdiobus_write_c45(struct mii_bus *bus, int phy_id, int devad,160 int regnum, u16 val)161{162 struct cavium_mdiobus *p = bus->priv;163 union cvmx_smix_cmd smi_cmd;164 union cvmx_smix_wr_dat smi_wr;165 int timeout = 1000;166 int r;167 168 r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);169 if (r < 0)170 return r;171 172 smi_wr.u64 = 0;173 smi_wr.s.dat = val;174 oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);175 176 smi_cmd.u64 = 0;177 smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_45_WRITE */178 smi_cmd.s.phy_adr = phy_id;179 smi_cmd.s.reg_adr = devad;180 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);181 182 do {183 /* Wait 1000 clocks so we don't saturate the RSL bus184 * doing reads.185 */186 __delay(1000);187 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);188 } while (smi_wr.s.pending && --timeout);189 190 if (timeout <= 0)191 return -EIO;192 193 return 0;194}195EXPORT_SYMBOL(cavium_mdiobus_write_c45);196 197MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");198MODULE_AUTHOR("David Daney");199MODULE_LICENSE("GPL v2");200