xref: /openbmc/linux/drivers/net/mdio/mdio-cavium.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1a9770eacSAndrew Lunn // SPDX-License-Identifier: GPL-2.0
2a9770eacSAndrew Lunn /*
3a9770eacSAndrew Lunn  * Copyright (C) 2009-2016 Cavium, Inc.
4a9770eacSAndrew Lunn  */
5a9770eacSAndrew Lunn 
6a9770eacSAndrew Lunn #include <linux/delay.h>
71bf34366SCalvin Johnson #include <linux/io.h>
8a9770eacSAndrew Lunn #include <linux/module.h>
9a9770eacSAndrew Lunn #include <linux/phy.h>
10a9770eacSAndrew Lunn 
11a9770eacSAndrew Lunn #include "mdio-cavium.h"
12a9770eacSAndrew Lunn 
cavium_mdiobus_set_mode(struct cavium_mdiobus * p,enum cavium_mdiobus_mode m)13a9770eacSAndrew Lunn static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p,
14a9770eacSAndrew Lunn 				    enum cavium_mdiobus_mode m)
15a9770eacSAndrew Lunn {
16a9770eacSAndrew Lunn 	union cvmx_smix_clk smi_clk;
17a9770eacSAndrew Lunn 
18a9770eacSAndrew Lunn 	if (m == p->mode)
19a9770eacSAndrew Lunn 		return;
20a9770eacSAndrew Lunn 
21a9770eacSAndrew Lunn 	smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK);
22a9770eacSAndrew Lunn 	smi_clk.s.mode = (m == C45) ? 1 : 0;
23a9770eacSAndrew Lunn 	smi_clk.s.preamble = 1;
24a9770eacSAndrew Lunn 	oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK);
25a9770eacSAndrew Lunn 	p->mode = m;
26a9770eacSAndrew Lunn }
27a9770eacSAndrew Lunn 
cavium_mdiobus_c45_addr(struct cavium_mdiobus * p,int phy_id,int devad,int regnum)28a9770eacSAndrew Lunn static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
2993641ecbSAndrew Lunn 				   int phy_id, int devad, int regnum)
30a9770eacSAndrew Lunn {
31a9770eacSAndrew Lunn 	union cvmx_smix_cmd smi_cmd;
32a9770eacSAndrew Lunn 	union cvmx_smix_wr_dat smi_wr;
33a9770eacSAndrew Lunn 	int timeout = 1000;
34a9770eacSAndrew Lunn 
35a9770eacSAndrew Lunn 	cavium_mdiobus_set_mode(p, C45);
36a9770eacSAndrew Lunn 
37a9770eacSAndrew Lunn 	smi_wr.u64 = 0;
38a9770eacSAndrew Lunn 	smi_wr.s.dat = regnum & 0xffff;
39a9770eacSAndrew Lunn 	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
40a9770eacSAndrew Lunn 
41a9770eacSAndrew Lunn 	smi_cmd.u64 = 0;
42a9770eacSAndrew Lunn 	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
43a9770eacSAndrew Lunn 	smi_cmd.s.phy_adr = phy_id;
4493641ecbSAndrew Lunn 	smi_cmd.s.reg_adr = devad;
45a9770eacSAndrew Lunn 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
46a9770eacSAndrew Lunn 
47a9770eacSAndrew Lunn 	do {
48a9770eacSAndrew Lunn 		/* Wait 1000 clocks so we don't saturate the RSL bus
49a9770eacSAndrew Lunn 		 * doing reads.
50a9770eacSAndrew Lunn 		 */
51a9770eacSAndrew Lunn 		__delay(1000);
52a9770eacSAndrew Lunn 		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
53a9770eacSAndrew Lunn 	} while (smi_wr.s.pending && --timeout);
54a9770eacSAndrew Lunn 
55a9770eacSAndrew Lunn 	if (timeout <= 0)
56a9770eacSAndrew Lunn 		return -EIO;
57a9770eacSAndrew Lunn 	return 0;
58a9770eacSAndrew Lunn }
59a9770eacSAndrew Lunn 
cavium_mdiobus_read_c22(struct mii_bus * bus,int phy_id,int regnum)6093641ecbSAndrew Lunn int cavium_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int regnum)
61a9770eacSAndrew Lunn {
62a9770eacSAndrew Lunn 	struct cavium_mdiobus *p = bus->priv;
63a9770eacSAndrew Lunn 	union cvmx_smix_cmd smi_cmd;
64a9770eacSAndrew Lunn 	union cvmx_smix_rd_dat smi_rd;
65a9770eacSAndrew Lunn 	int timeout = 1000;
66a9770eacSAndrew Lunn 
67a9770eacSAndrew Lunn 	cavium_mdiobus_set_mode(p, C22);
68a9770eacSAndrew Lunn 
69a9770eacSAndrew Lunn 	smi_cmd.u64 = 0;
70*0c68c8e5SAndrew Lunn 	smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
71a9770eacSAndrew Lunn 	smi_cmd.s.phy_adr = phy_id;
72a9770eacSAndrew Lunn 	smi_cmd.s.reg_adr = regnum;
73a9770eacSAndrew Lunn 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
74a9770eacSAndrew Lunn 
75a9770eacSAndrew Lunn 	do {
76a9770eacSAndrew Lunn 		/* Wait 1000 clocks so we don't saturate the RSL bus
77a9770eacSAndrew Lunn 		 * doing reads.
78a9770eacSAndrew Lunn 		 */
79a9770eacSAndrew Lunn 		__delay(1000);
80a9770eacSAndrew Lunn 		smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
81a9770eacSAndrew Lunn 	} while (smi_rd.s.pending && --timeout);
82a9770eacSAndrew Lunn 
83a9770eacSAndrew Lunn 	if (smi_rd.s.val)
84a9770eacSAndrew Lunn 		return smi_rd.s.dat;
85a9770eacSAndrew Lunn 	else
86a9770eacSAndrew Lunn 		return -EIO;
87a9770eacSAndrew Lunn }
8893641ecbSAndrew Lunn EXPORT_SYMBOL(cavium_mdiobus_read_c22);
89a9770eacSAndrew Lunn 
cavium_mdiobus_read_c45(struct mii_bus * bus,int phy_id,int devad,int regnum)9093641ecbSAndrew Lunn int cavium_mdiobus_read_c45(struct mii_bus *bus, int phy_id, int devad,
9193641ecbSAndrew Lunn 			    int regnum)
9293641ecbSAndrew Lunn {
9393641ecbSAndrew Lunn 	struct cavium_mdiobus *p = bus->priv;
9493641ecbSAndrew Lunn 	union cvmx_smix_cmd smi_cmd;
9593641ecbSAndrew Lunn 	union cvmx_smix_rd_dat smi_rd;
9693641ecbSAndrew Lunn 	int timeout = 1000;
9793641ecbSAndrew Lunn 	int r;
9893641ecbSAndrew Lunn 
9993641ecbSAndrew Lunn 	r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);
10093641ecbSAndrew Lunn 	if (r < 0)
10193641ecbSAndrew Lunn 		return r;
10293641ecbSAndrew Lunn 
10393641ecbSAndrew Lunn 	smi_cmd.u64 = 0;
10493641ecbSAndrew Lunn 	smi_cmd.s.phy_op = 3; /* MDIO_CLAUSE_45_READ */
10593641ecbSAndrew Lunn 	smi_cmd.s.phy_adr = phy_id;
10693641ecbSAndrew Lunn 	smi_cmd.s.reg_adr = regnum;
10793641ecbSAndrew Lunn 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
10893641ecbSAndrew Lunn 
10993641ecbSAndrew Lunn 	do {
11093641ecbSAndrew Lunn 		/* Wait 1000 clocks so we don't saturate the RSL bus
11193641ecbSAndrew Lunn 		 * doing reads.
11293641ecbSAndrew Lunn 		 */
11393641ecbSAndrew Lunn 		__delay(1000);
11493641ecbSAndrew Lunn 		smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
11593641ecbSAndrew Lunn 	} while (smi_rd.s.pending && --timeout);
11693641ecbSAndrew Lunn 
11793641ecbSAndrew Lunn 	if (smi_rd.s.val)
11893641ecbSAndrew Lunn 		return smi_rd.s.dat;
11993641ecbSAndrew Lunn 	else
12093641ecbSAndrew Lunn 		return -EIO;
12193641ecbSAndrew Lunn }
12293641ecbSAndrew Lunn EXPORT_SYMBOL(cavium_mdiobus_read_c45);
12393641ecbSAndrew Lunn 
cavium_mdiobus_write_c22(struct mii_bus * bus,int phy_id,int regnum,u16 val)12493641ecbSAndrew Lunn int cavium_mdiobus_write_c22(struct mii_bus *bus, int phy_id, int regnum,
12593641ecbSAndrew Lunn 			     u16 val)
126a9770eacSAndrew Lunn {
127a9770eacSAndrew Lunn 	struct cavium_mdiobus *p = bus->priv;
128a9770eacSAndrew Lunn 	union cvmx_smix_cmd smi_cmd;
129a9770eacSAndrew Lunn 	union cvmx_smix_wr_dat smi_wr;
130a9770eacSAndrew Lunn 	int timeout = 1000;
131a9770eacSAndrew Lunn 
132a9770eacSAndrew Lunn 	cavium_mdiobus_set_mode(p, C22);
133a9770eacSAndrew Lunn 
134a9770eacSAndrew Lunn 	smi_wr.u64 = 0;
135a9770eacSAndrew Lunn 	smi_wr.s.dat = val;
136a9770eacSAndrew Lunn 	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
137a9770eacSAndrew Lunn 
138a9770eacSAndrew Lunn 	smi_cmd.u64 = 0;
139*0c68c8e5SAndrew Lunn 	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
140a9770eacSAndrew Lunn 	smi_cmd.s.phy_adr = phy_id;
141a9770eacSAndrew Lunn 	smi_cmd.s.reg_adr = regnum;
142a9770eacSAndrew Lunn 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
143a9770eacSAndrew Lunn 
144a9770eacSAndrew Lunn 	do {
145a9770eacSAndrew Lunn 		/* Wait 1000 clocks so we don't saturate the RSL bus
146a9770eacSAndrew Lunn 		 * doing reads.
147a9770eacSAndrew Lunn 		 */
148a9770eacSAndrew Lunn 		__delay(1000);
149a9770eacSAndrew Lunn 		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
150a9770eacSAndrew Lunn 	} while (smi_wr.s.pending && --timeout);
151a9770eacSAndrew Lunn 
152a9770eacSAndrew Lunn 	if (timeout <= 0)
153a9770eacSAndrew Lunn 		return -EIO;
154a9770eacSAndrew Lunn 
155a9770eacSAndrew Lunn 	return 0;
156a9770eacSAndrew Lunn }
15793641ecbSAndrew Lunn EXPORT_SYMBOL(cavium_mdiobus_write_c22);
15893641ecbSAndrew Lunn 
cavium_mdiobus_write_c45(struct mii_bus * bus,int phy_id,int devad,int regnum,u16 val)15993641ecbSAndrew Lunn int cavium_mdiobus_write_c45(struct mii_bus *bus, int phy_id, int devad,
16093641ecbSAndrew Lunn 			     int regnum, u16 val)
16193641ecbSAndrew Lunn {
16293641ecbSAndrew Lunn 	struct cavium_mdiobus *p = bus->priv;
16393641ecbSAndrew Lunn 	union cvmx_smix_cmd smi_cmd;
16493641ecbSAndrew Lunn 	union cvmx_smix_wr_dat smi_wr;
16593641ecbSAndrew Lunn 	int timeout = 1000;
16693641ecbSAndrew Lunn 	int r;
16793641ecbSAndrew Lunn 
16893641ecbSAndrew Lunn 	r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);
16993641ecbSAndrew Lunn 	if (r < 0)
17093641ecbSAndrew Lunn 		return r;
17193641ecbSAndrew Lunn 
17293641ecbSAndrew Lunn 	smi_wr.u64 = 0;
17393641ecbSAndrew Lunn 	smi_wr.s.dat = val;
17493641ecbSAndrew Lunn 	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
17593641ecbSAndrew Lunn 
17693641ecbSAndrew Lunn 	smi_cmd.u64 = 0;
17793641ecbSAndrew Lunn 	smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_45_WRITE */
17893641ecbSAndrew Lunn 	smi_cmd.s.phy_adr = phy_id;
17993641ecbSAndrew Lunn 	smi_cmd.s.reg_adr = devad;
18093641ecbSAndrew Lunn 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
18193641ecbSAndrew Lunn 
18293641ecbSAndrew Lunn 	do {
18393641ecbSAndrew Lunn 		/* Wait 1000 clocks so we don't saturate the RSL bus
18493641ecbSAndrew Lunn 		 * doing reads.
18593641ecbSAndrew Lunn 		 */
18693641ecbSAndrew Lunn 		__delay(1000);
18793641ecbSAndrew Lunn 		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
18893641ecbSAndrew Lunn 	} while (smi_wr.s.pending && --timeout);
18993641ecbSAndrew Lunn 
19093641ecbSAndrew Lunn 	if (timeout <= 0)
19193641ecbSAndrew Lunn 		return -EIO;
19293641ecbSAndrew Lunn 
19393641ecbSAndrew Lunn 	return 0;
19493641ecbSAndrew Lunn }
19593641ecbSAndrew Lunn EXPORT_SYMBOL(cavium_mdiobus_write_c45);
196a9770eacSAndrew Lunn 
197a9770eacSAndrew Lunn MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");
198a9770eacSAndrew Lunn MODULE_AUTHOR("David Daney");
199a9770eacSAndrew Lunn MODULE_LICENSE("GPL v2");
200