1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2009-2016 Cavium, Inc.
6 #include <linux/delay.h>
7 #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 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
);
41 regnum
= (regnum
>> 16) & 0x1f;
44 smi_cmd
.s
.phy_op
= 0; /* MDIO_CLAUSE_45_ADDRESS */
45 smi_cmd
.s
.phy_adr
= phy_id
;
46 smi_cmd
.s
.reg_adr
= regnum
;
47 oct_mdio_writeq(smi_cmd
.u64
, p
->register_base
+ SMI_CMD
);
50 /* Wait 1000 clocks so we don't saturate the RSL bus
54 smi_wr
.u64
= oct_mdio_readq(p
->register_base
+ SMI_WR_DAT
);
55 } while (smi_wr
.s
.pending
&& --timeout
);
62 int cavium_mdiobus_read(struct mii_bus
*bus
, int phy_id
, int regnum
)
64 struct cavium_mdiobus
*p
= bus
->priv
;
65 union cvmx_smix_cmd smi_cmd
;
66 union cvmx_smix_rd_dat smi_rd
;
67 unsigned int op
= 1; /* MDIO_CLAUSE_22_READ */
70 if (regnum
& MII_ADDR_C45
) {
71 int r
= cavium_mdiobus_c45_addr(p
, phy_id
, regnum
);
76 regnum
= (regnum
>> 16) & 0x1f;
77 op
= 3; /* MDIO_CLAUSE_45_READ */
79 cavium_mdiobus_set_mode(p
, C22
);
83 smi_cmd
.s
.phy_op
= op
;
84 smi_cmd
.s
.phy_adr
= phy_id
;
85 smi_cmd
.s
.reg_adr
= regnum
;
86 oct_mdio_writeq(smi_cmd
.u64
, p
->register_base
+ SMI_CMD
);
89 /* Wait 1000 clocks so we don't saturate the RSL bus
93 smi_rd
.u64
= oct_mdio_readq(p
->register_base
+ SMI_RD_DAT
);
94 } while (smi_rd
.s
.pending
&& --timeout
);
101 EXPORT_SYMBOL(cavium_mdiobus_read
);
103 int cavium_mdiobus_write(struct mii_bus
*bus
, int phy_id
, int regnum
, u16 val
)
105 struct cavium_mdiobus
*p
= bus
->priv
;
106 union cvmx_smix_cmd smi_cmd
;
107 union cvmx_smix_wr_dat smi_wr
;
108 unsigned int op
= 0; /* MDIO_CLAUSE_22_WRITE */
111 if (regnum
& MII_ADDR_C45
) {
112 int r
= cavium_mdiobus_c45_addr(p
, phy_id
, regnum
);
117 regnum
= (regnum
>> 16) & 0x1f;
118 op
= 1; /* MDIO_CLAUSE_45_WRITE */
120 cavium_mdiobus_set_mode(p
, C22
);
125 oct_mdio_writeq(smi_wr
.u64
, p
->register_base
+ SMI_WR_DAT
);
128 smi_cmd
.s
.phy_op
= op
;
129 smi_cmd
.s
.phy_adr
= phy_id
;
130 smi_cmd
.s
.reg_adr
= regnum
;
131 oct_mdio_writeq(smi_cmd
.u64
, p
->register_base
+ SMI_CMD
);
134 /* Wait 1000 clocks so we don't saturate the RSL bus
138 smi_wr
.u64
= oct_mdio_readq(p
->register_base
+ SMI_WR_DAT
);
139 } while (smi_wr
.s
.pending
&& --timeout
);
146 EXPORT_SYMBOL(cavium_mdiobus_write
);
148 MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");
149 MODULE_AUTHOR("David Daney");
150 MODULE_LICENSE("GPL v2");