aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2009-10-14 15:04:38 -0400
committerRalf Baechle <ralf@linux-mips.org>2009-12-16 20:56:58 -0500
commit25d967b72a92d72b6e0263a0337dfc940bd6c044 (patch)
tree97900b2e687d8d868bd61ba7bc9d3acd3ce8b11a
parent0f7e64a3941fef0a5735da5184f3ccc0d234b580 (diff)
NET: Add driver for Octeon MDIO buses.
The Octeon SOC has two types of Ethernet ports, each type with its own driver. However, the PHYs for all the ports are controlled by a common MDIO bus. Because the mdio driver is not associated with a particular driver, but is instead a system level resource, we create s stand-alone driver for it. As for the driver, we put the register definitions in arch/mips/include/asm/octeon where most of the other Octeon register definitions live. This is a platform driver with the platform device for "mdio-octeon" being registered in the platform startup code. Signed-off-by: David Daney <ddaney@caviumnetworks.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/include/asm/octeon/cvmx-smix-defs.h178
-rw-r--r--drivers/net/phy/Kconfig11
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/mdio-octeon.c180
4 files changed, 370 insertions, 0 deletions
diff --git a/arch/mips/include/asm/octeon/cvmx-smix-defs.h b/arch/mips/include/asm/octeon/cvmx-smix-defs.h
new file mode 100644
index 000000000000..9ae45fcbe3e3
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-smix-defs.h
@@ -0,0 +1,178 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28#ifndef __CVMX_SMIX_DEFS_H__
29#define __CVMX_SMIX_DEFS_H__
30
31#define CVMX_SMIX_CLK(offset) \
32 CVMX_ADD_IO_SEG(0x0001180000001818ull + (((offset) & 1) * 256))
33#define CVMX_SMIX_CMD(offset) \
34 CVMX_ADD_IO_SEG(0x0001180000001800ull + (((offset) & 1) * 256))
35#define CVMX_SMIX_EN(offset) \
36 CVMX_ADD_IO_SEG(0x0001180000001820ull + (((offset) & 1) * 256))
37#define CVMX_SMIX_RD_DAT(offset) \
38 CVMX_ADD_IO_SEG(0x0001180000001810ull + (((offset) & 1) * 256))
39#define CVMX_SMIX_WR_DAT(offset) \
40 CVMX_ADD_IO_SEG(0x0001180000001808ull + (((offset) & 1) * 256))
41
42union cvmx_smix_clk {
43 uint64_t u64;
44 struct cvmx_smix_clk_s {
45 uint64_t reserved_25_63:39;
46 uint64_t mode:1;
47 uint64_t reserved_21_23:3;
48 uint64_t sample_hi:5;
49 uint64_t sample_mode:1;
50 uint64_t reserved_14_14:1;
51 uint64_t clk_idle:1;
52 uint64_t preamble:1;
53 uint64_t sample:4;
54 uint64_t phase:8;
55 } s;
56 struct cvmx_smix_clk_cn30xx {
57 uint64_t reserved_21_63:43;
58 uint64_t sample_hi:5;
59 uint64_t reserved_14_15:2;
60 uint64_t clk_idle:1;
61 uint64_t preamble:1;
62 uint64_t sample:4;
63 uint64_t phase:8;
64 } cn30xx;
65 struct cvmx_smix_clk_cn30xx cn31xx;
66 struct cvmx_smix_clk_cn30xx cn38xx;
67 struct cvmx_smix_clk_cn30xx cn38xxp2;
68 struct cvmx_smix_clk_cn50xx {
69 uint64_t reserved_25_63:39;
70 uint64_t mode:1;
71 uint64_t reserved_21_23:3;
72 uint64_t sample_hi:5;
73 uint64_t reserved_14_15:2;
74 uint64_t clk_idle:1;
75 uint64_t preamble:1;
76 uint64_t sample:4;
77 uint64_t phase:8;
78 } cn50xx;
79 struct cvmx_smix_clk_s cn52xx;
80 struct cvmx_smix_clk_cn50xx cn52xxp1;
81 struct cvmx_smix_clk_s cn56xx;
82 struct cvmx_smix_clk_cn50xx cn56xxp1;
83 struct cvmx_smix_clk_cn30xx cn58xx;
84 struct cvmx_smix_clk_cn30xx cn58xxp1;
85};
86
87union cvmx_smix_cmd {
88 uint64_t u64;
89 struct cvmx_smix_cmd_s {
90 uint64_t reserved_18_63:46;
91 uint64_t phy_op:2;
92 uint64_t reserved_13_15:3;
93 uint64_t phy_adr:5;
94 uint64_t reserved_5_7:3;
95 uint64_t reg_adr:5;
96 } s;
97 struct cvmx_smix_cmd_cn30xx {
98 uint64_t reserved_17_63:47;
99 uint64_t phy_op:1;
100 uint64_t reserved_13_15:3;
101 uint64_t phy_adr:5;
102 uint64_t reserved_5_7:3;
103 uint64_t reg_adr:5;
104 } cn30xx;
105 struct cvmx_smix_cmd_cn30xx cn31xx;
106 struct cvmx_smix_cmd_cn30xx cn38xx;
107 struct cvmx_smix_cmd_cn30xx cn38xxp2;
108 struct cvmx_smix_cmd_s cn50xx;
109 struct cvmx_smix_cmd_s cn52xx;
110 struct cvmx_smix_cmd_s cn52xxp1;
111 struct cvmx_smix_cmd_s cn56xx;
112 struct cvmx_smix_cmd_s cn56xxp1;
113 struct cvmx_smix_cmd_cn30xx cn58xx;
114 struct cvmx_smix_cmd_cn30xx cn58xxp1;
115};
116
117union cvmx_smix_en {
118 uint64_t u64;
119 struct cvmx_smix_en_s {
120 uint64_t reserved_1_63:63;
121 uint64_t en:1;
122 } s;
123 struct cvmx_smix_en_s cn30xx;
124 struct cvmx_smix_en_s cn31xx;
125 struct cvmx_smix_en_s cn38xx;
126 struct cvmx_smix_en_s cn38xxp2;
127 struct cvmx_smix_en_s cn50xx;
128 struct cvmx_smix_en_s cn52xx;
129 struct cvmx_smix_en_s cn52xxp1;
130 struct cvmx_smix_en_s cn56xx;
131 struct cvmx_smix_en_s cn56xxp1;
132 struct cvmx_smix_en_s cn58xx;
133 struct cvmx_smix_en_s cn58xxp1;
134};
135
136union cvmx_smix_rd_dat {
137 uint64_t u64;
138 struct cvmx_smix_rd_dat_s {
139 uint64_t reserved_18_63:46;
140 uint64_t pending:1;
141 uint64_t val:1;
142 uint64_t dat:16;
143 } s;
144 struct cvmx_smix_rd_dat_s cn30xx;
145 struct cvmx_smix_rd_dat_s cn31xx;
146 struct cvmx_smix_rd_dat_s cn38xx;
147 struct cvmx_smix_rd_dat_s cn38xxp2;
148 struct cvmx_smix_rd_dat_s cn50xx;
149 struct cvmx_smix_rd_dat_s cn52xx;
150 struct cvmx_smix_rd_dat_s cn52xxp1;
151 struct cvmx_smix_rd_dat_s cn56xx;
152 struct cvmx_smix_rd_dat_s cn56xxp1;
153 struct cvmx_smix_rd_dat_s cn58xx;
154 struct cvmx_smix_rd_dat_s cn58xxp1;
155};
156
157union cvmx_smix_wr_dat {
158 uint64_t u64;
159 struct cvmx_smix_wr_dat_s {
160 uint64_t reserved_18_63:46;
161 uint64_t pending:1;
162 uint64_t val:1;
163 uint64_t dat:16;
164 } s;
165 struct cvmx_smix_wr_dat_s cn30xx;
166 struct cvmx_smix_wr_dat_s cn31xx;
167 struct cvmx_smix_wr_dat_s cn38xx;
168 struct cvmx_smix_wr_dat_s cn38xxp2;
169 struct cvmx_smix_wr_dat_s cn50xx;
170 struct cvmx_smix_wr_dat_s cn52xx;
171 struct cvmx_smix_wr_dat_s cn52xxp1;
172 struct cvmx_smix_wr_dat_s cn56xx;
173 struct cvmx_smix_wr_dat_s cn56xxp1;
174 struct cvmx_smix_wr_dat_s cn58xx;
175 struct cvmx_smix_wr_dat_s cn58xxp1;
176};
177
178#endif
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d5d8e1c5bc91..fc5938ba3d78 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -115,4 +115,15 @@ config MDIO_GPIO
115 To compile this driver as a module, choose M here: the module 115 To compile this driver as a module, choose M here: the module
116 will be called mdio-gpio. 116 will be called mdio-gpio.
117 117
118config MDIO_OCTEON
119 tristate "Support for MDIO buses on Octeon SOCs"
120 depends on CPU_CAVIUM_OCTEON
121 default y
122 help
123
124 This module provides a driver for the Octeon MDIO busses.
125 It is required by the Octeon Ethernet device drivers.
126
127 If in doubt, say Y.
128
118endif # PHYLIB 129endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index edfaac48cbd5..1342585af381 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
20obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o 20obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
21obj-$(CONFIG_NATIONAL_PHY) += national.o 21obj-$(CONFIG_NATIONAL_PHY) += national.o
22obj-$(CONFIG_STE10XP) += ste10Xp.o 22obj-$(CONFIG_STE10XP) += ste10Xp.o
23obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
new file mode 100644
index 000000000000..61a4461cbda5
--- /dev/null
+++ b/drivers/net/phy/mdio-octeon.c
@@ -0,0 +1,180 @@
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 Cavium Networks
7 */
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/phy.h>
13
14#include <asm/octeon/octeon.h>
15#include <asm/octeon/cvmx-smix-defs.h>
16
17#define DRV_VERSION "1.0"
18#define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
19
20struct octeon_mdiobus {
21 struct mii_bus *mii_bus;
22 int unit;
23 int phy_irq[PHY_MAX_ADDR];
24};
25
26static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
27{
28 struct octeon_mdiobus *p = bus->priv;
29 union cvmx_smix_cmd smi_cmd;
30 union cvmx_smix_rd_dat smi_rd;
31 int timeout = 1000;
32
33 smi_cmd.u64 = 0;
34 smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
35 smi_cmd.s.phy_adr = phy_id;
36 smi_cmd.s.reg_adr = regnum;
37 cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
38
39 do {
40 /*
41 * Wait 1000 clocks so we don't saturate the RSL bus
42 * doing reads.
43 */
44 cvmx_wait(1000);
45 smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit));
46 } while (smi_rd.s.pending && --timeout);
47
48 if (smi_rd.s.val)
49 return smi_rd.s.dat;
50 else
51 return -EIO;
52}
53
54static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
55 int regnum, u16 val)
56{
57 struct octeon_mdiobus *p = bus->priv;
58 union cvmx_smix_cmd smi_cmd;
59 union cvmx_smix_wr_dat smi_wr;
60 int timeout = 1000;
61
62 smi_wr.u64 = 0;
63 smi_wr.s.dat = val;
64 cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64);
65
66 smi_cmd.u64 = 0;
67 smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
68 smi_cmd.s.phy_adr = phy_id;
69 smi_cmd.s.reg_adr = regnum;
70 cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
71
72 do {
73 /*
74 * Wait 1000 clocks so we don't saturate the RSL bus
75 * doing reads.
76 */
77 cvmx_wait(1000);
78 smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit));
79 } while (smi_wr.s.pending && --timeout);
80
81 if (timeout <= 0)
82 return -EIO;
83
84 return 0;
85}
86
87static int __init octeon_mdiobus_probe(struct platform_device *pdev)
88{
89 struct octeon_mdiobus *bus;
90 int i;
91 int err = -ENOENT;
92
93 bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
94 if (!bus)
95 return -ENOMEM;
96
97 /* The platform_device id is our unit number. */
98 bus->unit = pdev->id;
99
100 bus->mii_bus = mdiobus_alloc();
101
102 if (!bus->mii_bus)
103 goto err;
104
105 /*
106 * Standard Octeon evaluation boards don't support phy
107 * interrupts, we need to poll.
108 */
109 for (i = 0; i < PHY_MAX_ADDR; i++)
110 bus->phy_irq[i] = PHY_POLL;
111
112 bus->mii_bus->priv = bus;
113 bus->mii_bus->irq = bus->phy_irq;
114 bus->mii_bus->name = "mdio-octeon";
115 snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%x", bus->unit);
116 bus->mii_bus->parent = &pdev->dev;
117
118 bus->mii_bus->read = octeon_mdiobus_read;
119 bus->mii_bus->write = octeon_mdiobus_write;
120
121 dev_set_drvdata(&pdev->dev, bus);
122
123 err = mdiobus_register(bus->mii_bus);
124 if (err)
125 goto err_register;
126
127 dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
128
129 return 0;
130err_register:
131 mdiobus_free(bus->mii_bus);
132
133err:
134 devm_kfree(&pdev->dev, bus);
135 return err;
136}
137
138static int __exit octeon_mdiobus_remove(struct platform_device *pdev)
139{
140 struct octeon_mdiobus *bus;
141
142 bus = dev_get_drvdata(&pdev->dev);
143
144 mdiobus_unregister(bus->mii_bus);
145 mdiobus_free(bus->mii_bus);
146 return 0;
147}
148
149static struct platform_driver octeon_mdiobus_driver = {
150 .driver = {
151 .name = "mdio-octeon",
152 .owner = THIS_MODULE,
153 },
154 .probe = octeon_mdiobus_probe,
155 .remove = __exit_p(octeon_mdiobus_remove),
156};
157
158void octeon_mdiobus_force_mod_depencency(void)
159{
160 /* Let ethernet drivers force us to be loaded. */
161}
162EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency);
163
164static int __init octeon_mdiobus_mod_init(void)
165{
166 return platform_driver_register(&octeon_mdiobus_driver);
167}
168
169static void __exit octeon_mdiobus_mod_exit(void)
170{
171 platform_driver_unregister(&octeon_mdiobus_driver);
172}
173
174module_init(octeon_mdiobus_mod_init);
175module_exit(octeon_mdiobus_mod_exit);
176
177MODULE_DESCRIPTION(DRV_DESCRIPTION);
178MODULE_VERSION(DRV_VERSION);
179MODULE_AUTHOR("David Daney");
180MODULE_LICENSE("GPL");