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