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