Linux Audio

Check our new training course

Linux BSP upgrade and security maintenance

Need help to get security updates for your Linux BSP?
Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
  2/* Copyright 2019 NXP */
  3
  4#include <linux/fsl/enetc_mdio.h>
  5#include <linux/mdio.h>
  6#include <linux/of_mdio.h>
  7#include <linux/iopoll.h>
  8#include <linux/of.h>
  9
 10#include "enetc_pf.h"
 11
 12#define	ENETC_MDIO_CFG	0x0	/* MDIO configuration and status */
 13#define	ENETC_MDIO_CTL	0x4	/* MDIO control */
 14#define	ENETC_MDIO_DATA	0x8	/* MDIO data */
 15#define	ENETC_MDIO_ADDR	0xc	/* MDIO address */
 16
 17#define MDIO_CFG_CLKDIV(x)	((((x) >> 1) & 0xff) << 8)
 18#define MDIO_CFG_BSY		BIT(0)
 19#define MDIO_CFG_RD_ER		BIT(1)
 20#define MDIO_CFG_HOLD(x)	(((x) << 2) & GENMASK(4, 2))
 21#define MDIO_CFG_ENC45		BIT(6)
 22 /* external MDIO only - driven on neg MDC edge */
 23#define MDIO_CFG_NEG		BIT(23)
 24
 25#define ENETC_EMDIO_CFG \
 26	(MDIO_CFG_HOLD(2) | \
 27	 MDIO_CFG_CLKDIV(258) | \
 28	 MDIO_CFG_NEG)
 29
 30#define MDIO_CTL_DEV_ADDR(x)	((x) & 0x1f)
 31#define MDIO_CTL_PORT_ADDR(x)	(((x) & 0x1f) << 5)
 32#define MDIO_CTL_READ		BIT(15)
 33
 34static inline u32 enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off)
 35{
 36	return enetc_port_rd_mdio(mdio_priv->hw, mdio_priv->mdio_base + off);
 37}
 38
 39static inline void enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off,
 40				 u32 val)
 41{
 42	enetc_port_wr_mdio(mdio_priv->hw, mdio_priv->mdio_base + off, val);
 43}
 44
 45static bool enetc_mdio_is_busy(struct enetc_mdio_priv *mdio_priv)
 46{
 47	return enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_BSY;
 48}
 49
 50static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv)
 51{
 52	bool is_busy;
 53
 54	return readx_poll_timeout(enetc_mdio_is_busy, mdio_priv,
 55				  is_busy, !is_busy, 10, 10 * 1000);
 56}
 57
 58int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum,
 59			 u16 value)
 60{
 61	struct enetc_mdio_priv *mdio_priv = bus->priv;
 62	u32 mdio_ctl, mdio_cfg;
 63	u16 dev_addr;
 64	int ret;
 65
 66	mdio_cfg = ENETC_EMDIO_CFG;
 67	dev_addr = regnum & 0x1f;
 68	mdio_cfg &= ~MDIO_CFG_ENC45;
 69
 70	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
 71
 72	ret = enetc_mdio_wait_complete(mdio_priv);
 73	if (ret)
 74		return ret;
 75
 76	/* set port and dev addr */
 77	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
 78	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
 79
 80	/* write the value */
 81	enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value);
 82
 83	ret = enetc_mdio_wait_complete(mdio_priv);
 84	if (ret)
 85		return ret;
 86
 87	return 0;
 88}
 89EXPORT_SYMBOL_GPL(enetc_mdio_write_c22);
 90
 91int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
 92			 int regnum, u16 value)
 93{
 94	struct enetc_mdio_priv *mdio_priv = bus->priv;
 95	u32 mdio_ctl, mdio_cfg;
 96	int ret;
 97
 98	mdio_cfg = ENETC_EMDIO_CFG;
 99	mdio_cfg |= MDIO_CFG_ENC45;
100
101	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
102
103	ret = enetc_mdio_wait_complete(mdio_priv);
104	if (ret)
105		return ret;
106
107	/* set port and dev addr */
108	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
109	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
110
111	/* set the register address */
112	enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
113
114	ret = enetc_mdio_wait_complete(mdio_priv);
115	if (ret)
116		return ret;
117
118	/* write the value */
119	enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value);
120
121	ret = enetc_mdio_wait_complete(mdio_priv);
122	if (ret)
123		return ret;
124
125	return 0;
126}
127EXPORT_SYMBOL_GPL(enetc_mdio_write_c45);
128
129int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
130{
131	struct enetc_mdio_priv *mdio_priv = bus->priv;
132	u32 mdio_ctl, mdio_cfg;
133	u16 dev_addr, value;
134	int ret;
135
136	mdio_cfg = ENETC_EMDIO_CFG;
137	dev_addr = regnum & 0x1f;
138	mdio_cfg &= ~MDIO_CFG_ENC45;
139
140	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
141
142	ret = enetc_mdio_wait_complete(mdio_priv);
143	if (ret)
144		return ret;
145
146	/* set port and device addr */
147	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
148	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
149
150	/* initiate the read */
151	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
152
153	ret = enetc_mdio_wait_complete(mdio_priv);
154	if (ret)
155		return ret;
156
157	/* return all Fs if nothing was there */
158	if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) {
159		dev_dbg(&bus->dev,
160			"Error while reading PHY%d reg at %d.%d\n",
161			phy_id, dev_addr, regnum);
162		return 0xffff;
163	}
164
165	value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff;
166
167	return value;
168}
169EXPORT_SYMBOL_GPL(enetc_mdio_read_c22);
170
171int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,
172			int regnum)
173{
174	struct enetc_mdio_priv *mdio_priv = bus->priv;
175	u32 mdio_ctl, mdio_cfg;
176	u16 value;
177	int ret;
178
179	mdio_cfg = ENETC_EMDIO_CFG;
180	mdio_cfg |= MDIO_CFG_ENC45;
181
182	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
183
184	ret = enetc_mdio_wait_complete(mdio_priv);
185	if (ret)
186		return ret;
187
188	/* set port and device addr */
189	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
190	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
191
192	/* set the register address */
193	enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
194
195	ret = enetc_mdio_wait_complete(mdio_priv);
196	if (ret)
197		return ret;
198
199	/* initiate the read */
200	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
201
202	ret = enetc_mdio_wait_complete(mdio_priv);
203	if (ret)
204		return ret;
205
206	/* return all Fs if nothing was there */
207	if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) {
208		dev_dbg(&bus->dev,
209			"Error while reading PHY%d reg at %d.%d\n",
210			phy_id, dev_addr, regnum);
211		return 0xffff;
212	}
213
214	value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff;
215
216	return value;
217}
218EXPORT_SYMBOL_GPL(enetc_mdio_read_c45);
219
220struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
221{
222	struct enetc_hw *hw;
223
224	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
225	if (!hw)
226		return ERR_PTR(-ENOMEM);
227
228	hw->port = port_regs;
229
230	return hw;
231}
232EXPORT_SYMBOL_GPL(enetc_hw_alloc);
233
234/* Lock for MDIO access errata on LS1028A */
235DEFINE_RWLOCK(enetc_mdio_lock);
236EXPORT_SYMBOL_GPL(enetc_mdio_lock);