blob: f4cb86d10a7463f5cdd8198c4493396dcdcfe728 [file] [log] [blame]
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -05001// 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>
Simon Glassf7ae49f2020-05-10 11:40:05 -06009#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070010#include <malloc.h>
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -050011#include <asm/io.h>
12#include <miiphy.h>
13#include <wait_bit.h>
Simon Glasscd93d622020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060015#include <linux/delay.h>
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -050016
17struct cpsw_mdio_regs {
18 u32 version;
19 u32 control;
20#define CONTROL_IDLE BIT(31)
21#define CONTROL_ENABLE BIT(30)
22#define CONTROL_FAULT BIT(19)
23#define CONTROL_FAULT_ENABLE BIT(18)
24#define CONTROL_DIV_MASK GENMASK(15, 0)
25
26 u32 alive;
27 u32 link;
28 u32 linkintraw;
29 u32 linkintmasked;
30 u32 __reserved_0[2];
31 u32 userintraw;
32 u32 userintmasked;
33 u32 userintmaskset;
34 u32 userintmaskclr;
35 u32 __reserved_1[20];
36
37 struct {
38 u32 access;
39 u32 physel;
40#define USERACCESS_GO BIT(31)
41#define USERACCESS_WRITE BIT(30)
42#define USERACCESS_ACK BIT(29)
43#define USERACCESS_READ (0)
44#define USERACCESS_PHY_REG_SHIFT (21)
45#define USERACCESS_PHY_ADDR_SHIFT (16)
46#define USERACCESS_DATA GENMASK(15, 0)
47 } user[0];
48};
49
50#define CPSW_MDIO_DIV_DEF 0xff
51#define PHY_REG_MASK 0x1f
52#define PHY_ID_MASK 0x1f
53
54/*
55 * This timeout definition is a worst-case ultra defensive measure against
56 * unexpected controller lock ups. Ideally, we should never ever hit this
57 * scenario in practice.
58 */
59#define CPSW_MDIO_TIMEOUT 100 /* msecs */
60
61struct cpsw_mdio {
62 struct cpsw_mdio_regs *regs;
63 struct mii_dev *bus;
64 int div;
65};
66
67/* wait until hardware is ready for another user access */
68static int cpsw_mdio_wait_for_user_access(struct cpsw_mdio *mdio)
69{
70 return wait_for_bit_le32(&mdio->regs->user[0].access,
71 USERACCESS_GO, false,
72 CPSW_MDIO_TIMEOUT, false);
73}
74
75static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
76 int dev_addr, int phy_reg)
77{
78 struct cpsw_mdio *mdio = bus->priv;
79 int data, ret;
80 u32 reg;
81
82 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
83 return -EINVAL;
84
85 ret = cpsw_mdio_wait_for_user_access(mdio);
86 if (ret)
87 return ret;
88 reg = (USERACCESS_GO | USERACCESS_READ |
89 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
90 (phy_id << USERACCESS_PHY_ADDR_SHIFT));
91 writel(reg, &mdio->regs->user[0].access);
92 ret = cpsw_mdio_wait_for_user_access(mdio);
93 if (ret)
94 return ret;
95
96 reg = readl(&mdio->regs->user[0].access);
97 data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1;
98 return data;
99}
100
101static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr,
102 int phy_reg, u16 data)
103{
104 struct cpsw_mdio *mdio = bus->priv;
105 u32 reg;
106 int ret;
107
108 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
109 return -EINVAL;
110
111 ret = cpsw_mdio_wait_for_user_access(mdio);
112 if (ret)
113 return ret;
114 reg = (USERACCESS_GO | USERACCESS_WRITE |
115 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
116 (phy_id << USERACCESS_PHY_ADDR_SHIFT) |
117 (data & USERACCESS_DATA));
118 writel(reg, &mdio->regs->user[0].access);
119
120 return cpsw_mdio_wait_for_user_access(mdio);
121}
122
123u32 cpsw_mdio_get_alive(struct mii_dev *bus)
124{
125 struct cpsw_mdio *mdio = bus->priv;
126 u32 val;
127
128 val = readl(&mdio->regs->control);
129 return val & GENMASK(15, 0);
130}
131
Keerthy45e8c052019-07-09 10:30:33 +0530132struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base,
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -0500133 u32 bus_freq, int fck_freq)
134{
135 struct cpsw_mdio *cpsw_mdio;
136 int ret;
137
138 cpsw_mdio = calloc(1, sizeof(*cpsw_mdio));
139 if (!cpsw_mdio) {
140 debug("failed to alloc cpsw_mdio\n");
141 return NULL;
142 }
143
144 cpsw_mdio->bus = mdio_alloc();
145 if (!cpsw_mdio->bus) {
146 debug("failed to alloc mii bus\n");
147 free(cpsw_mdio);
148 return NULL;
149 }
150
Keerthy45e8c052019-07-09 10:30:33 +0530151 cpsw_mdio->regs = (struct cpsw_mdio_regs *)(uintptr_t)mdio_base;
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -0500152
153 if (!bus_freq || !fck_freq)
154 cpsw_mdio->div = CPSW_MDIO_DIV_DEF;
155 else
156 cpsw_mdio->div = (fck_freq / bus_freq) - 1;
157 cpsw_mdio->div &= CONTROL_DIV_MASK;
158
159 /* set enable and clock divider */
160 writel(cpsw_mdio->div | CONTROL_ENABLE | CONTROL_FAULT |
161 CONTROL_FAULT_ENABLE, &cpsw_mdio->regs->control);
162 wait_for_bit_le32(&cpsw_mdio->regs->control,
163 CONTROL_IDLE, false, CPSW_MDIO_TIMEOUT, true);
164
165 /*
166 * wait for scan logic to settle:
167 * the scan time consists of (a) a large fixed component, and (b) a
168 * small component that varies with the mii bus frequency. These
169 * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
170 * silicon. Since the effect of (b) was found to be largely
171 * negligible, we keep things simple here.
172 */
173 mdelay(1);
174
175 cpsw_mdio->bus->read = cpsw_mdio_read;
176 cpsw_mdio->bus->write = cpsw_mdio_write;
177 cpsw_mdio->bus->priv = cpsw_mdio;
178 snprintf(cpsw_mdio->bus->name, sizeof(cpsw_mdio->bus->name), name);
179
180 ret = mdio_register(cpsw_mdio->bus);
181 if (ret < 0) {
182 debug("failed to register mii bus\n");
183 goto free_bus;
184 }
185
186 return cpsw_mdio->bus;
187
188free_bus:
189 mdio_free(cpsw_mdio->bus);
190 free(cpsw_mdio);
191 return NULL;
192}
193
194void cpsw_mdio_free(struct mii_dev *bus)
195{
196 struct cpsw_mdio *mdio = bus->priv;
197 u32 reg;
198
199 /* disable mdio */
200 reg = readl(&mdio->regs->control);
201 reg &= ~CONTROL_ENABLE;
202 writel(reg, &mdio->regs->control);
203
204 mdio_unregister(bus);
205 mdio_free(bus);
206 free(mdio);
207}