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