linux/drivers/net/phy/mdio-cavium.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2009-2016 Cavium, Inc.
   7 */
   8
   9#include <linux/delay.h>
  10#include <linux/module.h>
  11#include <linux/phy.h>
  12#include <linux/io.h>
  13
  14#include "mdio-cavium.h"
  15
  16static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p,
  17                                    enum cavium_mdiobus_mode m)
  18{
  19        union cvmx_smix_clk smi_clk;
  20
  21        if (m == p->mode)
  22                return;
  23
  24        smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK);
  25        smi_clk.s.mode = (m == C45) ? 1 : 0;
  26        smi_clk.s.preamble = 1;
  27        oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK);
  28        p->mode = m;
  29}
  30
  31static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
  32                                   int phy_id, int regnum)
  33{
  34        union cvmx_smix_cmd smi_cmd;
  35        union cvmx_smix_wr_dat smi_wr;
  36        int timeout = 1000;
  37
  38        cavium_mdiobus_set_mode(p, C45);
  39
  40        smi_wr.u64 = 0;
  41        smi_wr.s.dat = regnum & 0xffff;
  42        oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
  43
  44        regnum = (regnum >> 16) & 0x1f;
  45
  46        smi_cmd.u64 = 0;
  47        smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
  48        smi_cmd.s.phy_adr = phy_id;
  49        smi_cmd.s.reg_adr = regnum;
  50        oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
  51
  52        do {
  53                /* Wait 1000 clocks so we don't saturate the RSL bus
  54                 * doing reads.
  55                 */
  56                __delay(1000);
  57                smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
  58        } while (smi_wr.s.pending && --timeout);
  59
  60        if (timeout <= 0)
  61                return -EIO;
  62        return 0;
  63}
  64
  65int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
  66{
  67        struct cavium_mdiobus *p = bus->priv;
  68        union cvmx_smix_cmd smi_cmd;
  69        union cvmx_smix_rd_dat smi_rd;
  70        unsigned int op = 1; /* MDIO_CLAUSE_22_READ */
  71        int timeout = 1000;
  72
  73        if (regnum & MII_ADDR_C45) {
  74                int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
  75
  76                if (r < 0)
  77                        return r;
  78
  79                regnum = (regnum >> 16) & 0x1f;
  80                op = 3; /* MDIO_CLAUSE_45_READ */
  81        } else {
  82                cavium_mdiobus_set_mode(p, C22);
  83        }
  84
  85        smi_cmd.u64 = 0;
  86        smi_cmd.s.phy_op = op;
  87        smi_cmd.s.phy_adr = phy_id;
  88        smi_cmd.s.reg_adr = regnum;
  89        oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
  90
  91        do {
  92                /* Wait 1000 clocks so we don't saturate the RSL bus
  93                 * doing reads.
  94                 */
  95                __delay(1000);
  96                smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
  97        } while (smi_rd.s.pending && --timeout);
  98
  99        if (smi_rd.s.val)
 100                return smi_rd.s.dat;
 101        else
 102                return -EIO;
 103}
 104EXPORT_SYMBOL(cavium_mdiobus_read);
 105
 106int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
 107{
 108        struct cavium_mdiobus *p = bus->priv;
 109        union cvmx_smix_cmd smi_cmd;
 110        union cvmx_smix_wr_dat smi_wr;
 111        unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */
 112        int timeout = 1000;
 113
 114        if (regnum & MII_ADDR_C45) {
 115                int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
 116
 117                if (r < 0)
 118                        return r;
 119
 120                regnum = (regnum >> 16) & 0x1f;
 121                op = 1; /* MDIO_CLAUSE_45_WRITE */
 122        } else {
 123                cavium_mdiobus_set_mode(p, C22);
 124        }
 125
 126        smi_wr.u64 = 0;
 127        smi_wr.s.dat = val;
 128        oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
 129
 130        smi_cmd.u64 = 0;
 131        smi_cmd.s.phy_op = op;
 132        smi_cmd.s.phy_adr = phy_id;
 133        smi_cmd.s.reg_adr = regnum;
 134        oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
 135
 136        do {
 137                /* Wait 1000 clocks so we don't saturate the RSL bus
 138                 * doing reads.
 139                 */
 140                __delay(1000);
 141                smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
 142        } while (smi_wr.s.pending && --timeout);
 143
 144        if (timeout <= 0)
 145                return -EIO;
 146
 147        return 0;
 148}
 149EXPORT_SYMBOL(cavium_mdiobus_write);
 150
 151MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");
 152MODULE_AUTHOR("David Daney");
 153MODULE_LICENSE("GPL");
 154