1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2009-2016 Cavium, Inc.
6 #include <linux/delay.h>
8 #include <linux/module.h>
11 #include "mdio-cavium.h"
13 static void cavium_mdiobus_set_mode(struct cavium_mdiobus
*p
,
14 enum cavium_mdiobus_mode m
)
16 union cvmx_smix_clk smi_clk
;
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
);
28 static int cavium_mdiobus_c45_addr(struct cavium_mdiobus
*p
,
29 int phy_id
, int devad
, int regnum
)
31 union cvmx_smix_cmd smi_cmd
;
32 union cvmx_smix_wr_dat smi_wr
;
35 cavium_mdiobus_set_mode(p
, C45
);
38 smi_wr
.s
.dat
= regnum
& 0xffff;
39 oct_mdio_writeq(smi_wr
.u64
, p
->register_base
+ SMI_WR_DAT
);
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
);
48 /* Wait 1000 clocks so we don't saturate the RSL bus
52 smi_wr
.u64
= oct_mdio_readq(p
->register_base
+ SMI_WR_DAT
);
53 } while (smi_wr
.s
.pending
&& --timeout
);
60 int cavium_mdiobus_read_c22(struct mii_bus
*bus
, int phy_id
, int regnum
)
62 struct cavium_mdiobus
*p
= bus
->priv
;
63 union cvmx_smix_cmd smi_cmd
;
64 union cvmx_smix_rd_dat smi_rd
;
67 cavium_mdiobus_set_mode(p
, C22
);
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
);
76 /* Wait 1000 clocks so we don't saturate the RSL bus
80 smi_rd
.u64
= oct_mdio_readq(p
->register_base
+ SMI_RD_DAT
);
81 } while (smi_rd
.s
.pending
&& --timeout
);
88 EXPORT_SYMBOL(cavium_mdiobus_read_c22
);
90 int cavium_mdiobus_read_c45(struct mii_bus
*bus
, int phy_id
, int devad
,
93 struct cavium_mdiobus
*p
= bus
->priv
;
94 union cvmx_smix_cmd smi_cmd
;
95 union cvmx_smix_rd_dat smi_rd
;
99 r
= cavium_mdiobus_c45_addr(p
, phy_id
, devad
, regnum
);
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
);
110 /* Wait 1000 clocks so we don't saturate the RSL bus
114 smi_rd
.u64
= oct_mdio_readq(p
->register_base
+ SMI_RD_DAT
);
115 } while (smi_rd
.s
.pending
&& --timeout
);
122 EXPORT_SYMBOL(cavium_mdiobus_read_c45
);
124 int cavium_mdiobus_write_c22(struct mii_bus
*bus
, int phy_id
, int regnum
,
127 struct cavium_mdiobus
*p
= bus
->priv
;
128 union cvmx_smix_cmd smi_cmd
;
129 union cvmx_smix_wr_dat smi_wr
;
132 cavium_mdiobus_set_mode(p
, C22
);
136 oct_mdio_writeq(smi_wr
.u64
, p
->register_base
+ SMI_WR_DAT
);
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
);
145 /* Wait 1000 clocks so we don't saturate the RSL bus
149 smi_wr
.u64
= oct_mdio_readq(p
->register_base
+ SMI_WR_DAT
);
150 } while (smi_wr
.s
.pending
&& --timeout
);
157 EXPORT_SYMBOL(cavium_mdiobus_write_c22
);
159 int cavium_mdiobus_write_c45(struct mii_bus
*bus
, int phy_id
, int devad
,
162 struct cavium_mdiobus
*p
= bus
->priv
;
163 union cvmx_smix_cmd smi_cmd
;
164 union cvmx_smix_wr_dat smi_wr
;
168 r
= cavium_mdiobus_c45_addr(p
, phy_id
, devad
, regnum
);
174 oct_mdio_writeq(smi_wr
.u64
, p
->register_base
+ SMI_WR_DAT
);
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
);
183 /* Wait 1000 clocks so we don't saturate the RSL bus
187 smi_wr
.u64
= oct_mdio_readq(p
->register_base
+ SMI_WR_DAT
);
188 } while (smi_wr
.s
.pending
&& --timeout
);
195 EXPORT_SYMBOL(cavium_mdiobus_write_c45
);
197 MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");
198 MODULE_AUTHOR("David Daney");
199 MODULE_LICENSE("GPL v2");