aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrygorii Strashko2018-10-31 16:21:43 -0500
committerJoe Hershberger2018-11-05 10:42:00 -0600
commit6c4bbccc6ed22464ef70500025e109ce63adaf74 (patch)
tree4d25a2238a0cdce0ac486baac5b747af2087cb02 /drivers
parentcbec53b434d290689ece1111f395d97f27f5c17f (diff)
downloadu-boot-6c4bbccc6ed22464ef70500025e109ce63adaf74.tar.gz
u-boot-6c4bbccc6ed22464ef70500025e109ce63adaf74.tar.xz
u-boot-6c4bbccc6ed22464ef70500025e109ce63adaf74.zip
driver: net: ti: introduce common mdio support library
All existing TI SoCs network HW have similar MDIO implementation, so introduce common mdio support library which can be reused by TI networking drivers. Reviewed-by: Tom Rini <trini@konsulko.com> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ti/Makefile2
-rw-r--r--drivers/net/ti/cpsw_mdio.c203
-rw-r--r--drivers/net/ti/cpsw_mdio.h18
3 files changed, 222 insertions, 1 deletions
diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile
index 4ab4a27498..d2b6f2022b 100644
--- a/drivers/net/ti/Makefile
+++ b/drivers/net/ti/Makefile
@@ -2,6 +2,6 @@
2# 2#
3# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 3# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
4 4
5obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o 5obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o
6obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o 6obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
7obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o 7obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
diff --git a/drivers/net/ti/cpsw_mdio.c b/drivers/net/ti/cpsw_mdio.c
new file mode 100644
index 0000000000..70f547e6d7
--- /dev/null
+++ b/drivers/net/ti/cpsw_mdio.c
@@ -0,0 +1,203 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * CPSW MDIO generic driver for TI AMxx/K2x/EMAC devices.
4 *
5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6 */
7
8#include <common.h>
9#include <asm/io.h>
10#include <miiphy.h>
11#include <wait_bit.h>
12
13struct cpsw_mdio_regs {
14 u32 version;
15 u32 control;
16#define CONTROL_IDLE BIT(31)
17#define CONTROL_ENABLE BIT(30)
18#define CONTROL_FAULT BIT(19)
19#define CONTROL_FAULT_ENABLE BIT(18)
20#define CONTROL_DIV_MASK GENMASK(15, 0)
21
22 u32 alive;
23 u32 link;
24 u32 linkintraw;
25 u32 linkintmasked;
26 u32 __reserved_0[2];
27 u32 userintraw;
28 u32 userintmasked;
29 u32 userintmaskset;
30 u32 userintmaskclr;
31 u32 __reserved_1[20];
32
33 struct {
34 u32 access;
35 u32 physel;
36#define USERACCESS_GO BIT(31)
37#define USERACCESS_WRITE BIT(30)
38#define USERACCESS_ACK BIT(29)
39#define USERACCESS_READ (0)
40#define USERACCESS_PHY_REG_SHIFT (21)
41#define USERACCESS_PHY_ADDR_SHIFT (16)
42#define USERACCESS_DATA GENMASK(15, 0)
43 } user[0];
44};
45
46#define CPSW_MDIO_DIV_DEF 0xff
47#define PHY_REG_MASK 0x1f
48#define PHY_ID_MASK 0x1f
49
50/*
51 * This timeout definition is a worst-case ultra defensive measure against
52 * unexpected controller lock ups. Ideally, we should never ever hit this
53 * scenario in practice.
54 */
55#define CPSW_MDIO_TIMEOUT 100 /* msecs */
56
57struct cpsw_mdio {
58 struct cpsw_mdio_regs *regs;
59 struct mii_dev *bus;
60 int div;
61};
62
63/* wait until hardware is ready for another user access */
64static int cpsw_mdio_wait_for_user_access(struct cpsw_mdio *mdio)
65{
66 return wait_for_bit_le32(&mdio->regs->user[0].access,
67 USERACCESS_GO, false,
68 CPSW_MDIO_TIMEOUT, false);
69}
70
71static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
72 int dev_addr, int phy_reg)
73{
74 struct cpsw_mdio *mdio = bus->priv;
75 int data, ret;
76 u32 reg;
77
78 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
79 return -EINVAL;
80
81 ret = cpsw_mdio_wait_for_user_access(mdio);
82 if (ret)
83 return ret;
84 reg = (USERACCESS_GO | USERACCESS_READ |
85 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
86 (phy_id << USERACCESS_PHY_ADDR_SHIFT));
87 writel(reg, &mdio->regs->user[0].access);
88 ret = cpsw_mdio_wait_for_user_access(mdio);
89 if (ret)
90 return ret;
91
92 reg = readl(&mdio->regs->user[0].access);
93 data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1;
94 return data;
95}
96
97static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr,
98 int phy_reg, u16 data)
99{
100 struct cpsw_mdio *mdio = bus->priv;
101 u32 reg;
102 int ret;
103
104 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
105 return -EINVAL;
106
107 ret = cpsw_mdio_wait_for_user_access(mdio);
108 if (ret)
109 return ret;
110 reg = (USERACCESS_GO | USERACCESS_WRITE |
111 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
112 (phy_id << USERACCESS_PHY_ADDR_SHIFT) |
113 (data & USERACCESS_DATA));
114 writel(reg, &mdio->regs->user[0].access);
115
116 return cpsw_mdio_wait_for_user_access(mdio);
117}
118
119u32 cpsw_mdio_get_alive(struct mii_dev *bus)
120{
121 struct cpsw_mdio *mdio = bus->priv;
122 u32 val;
123
124 val = readl(&mdio->regs->control);
125 return val & GENMASK(15, 0);
126}
127
128struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base,
129 u32 bus_freq, int fck_freq)
130{
131 struct cpsw_mdio *cpsw_mdio;
132 int ret;
133
134 cpsw_mdio = calloc(1, sizeof(*cpsw_mdio));
135 if (!cpsw_mdio) {
136 debug("failed to alloc cpsw_mdio\n");
137 return NULL;
138 }
139
140 cpsw_mdio->bus = mdio_alloc();
141 if (!cpsw_mdio->bus) {
142 debug("failed to alloc mii bus\n");
143 free(cpsw_mdio);
144 return NULL;
145 }
146
147 cpsw_mdio->regs = (struct cpsw_mdio_regs *)mdio_base;
148
149 if (!bus_freq || !fck_freq)
150 cpsw_mdio->div = CPSW_MDIO_DIV_DEF;
151 else
152 cpsw_mdio->div = (fck_freq / bus_freq) - 1;
153 cpsw_mdio->div &= CONTROL_DIV_MASK;
154
155 /* set enable and clock divider */
156 writel(cpsw_mdio->div | CONTROL_ENABLE | CONTROL_FAULT |
157 CONTROL_FAULT_ENABLE, &cpsw_mdio->regs->control);
158 wait_for_bit_le32(&cpsw_mdio->regs->control,
159 CONTROL_IDLE, false, CPSW_MDIO_TIMEOUT, true);
160
161 /*
162 * wait for scan logic to settle:
163 * the scan time consists of (a) a large fixed component, and (b) a
164 * small component that varies with the mii bus frequency. These
165 * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
166 * silicon. Since the effect of (b) was found to be largely
167 * negligible, we keep things simple here.
168 */
169 mdelay(1);
170
171 cpsw_mdio->bus->read = cpsw_mdio_read;
172 cpsw_mdio->bus->write = cpsw_mdio_write;
173 cpsw_mdio->bus->priv = cpsw_mdio;
174 snprintf(cpsw_mdio->bus->name, sizeof(cpsw_mdio->bus->name), name);
175
176 ret = mdio_register(cpsw_mdio->bus);
177 if (ret < 0) {
178 debug("failed to register mii bus\n");
179 goto free_bus;
180 }
181
182 return cpsw_mdio->bus;
183
184free_bus:
185 mdio_free(cpsw_mdio->bus);
186 free(cpsw_mdio);
187 return NULL;
188}
189
190void cpsw_mdio_free(struct mii_dev *bus)
191{
192 struct cpsw_mdio *mdio = bus->priv;
193 u32 reg;
194
195 /* disable mdio */
196 reg = readl(&mdio->regs->control);
197 reg &= ~CONTROL_ENABLE;
198 writel(reg, &mdio->regs->control);
199
200 mdio_unregister(bus);
201 mdio_free(bus);
202 free(mdio);
203}
diff --git a/drivers/net/ti/cpsw_mdio.h b/drivers/net/ti/cpsw_mdio.h
new file mode 100644
index 0000000000..4a76d4e5c5
--- /dev/null
+++ b/drivers/net/ti/cpsw_mdio.h
@@ -0,0 +1,18 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * CPSW MDIO generic driver API for TI AMxx/K2x/EMAC devices.
4 *
5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6 */
7
8#ifndef CPSW_MDIO_H_
9#define CPSW_MDIO_H_
10
11struct cpsw_mdio;
12
13struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base,
14 u32 bus_freq, int fck_freq);
15void cpsw_mdio_free(struct mii_dev *bus);
16u32 cpsw_mdio_get_alive(struct mii_dev *bus);
17
18#endif /* CPSW_MDIO_H_ */