cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

enetc_mdio.c (4388B)


      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(struct mii_bus *bus, int phy_id, int regnum, u16 value)
     59{
     60	struct enetc_mdio_priv *mdio_priv = bus->priv;
     61	u32 mdio_ctl, mdio_cfg;
     62	u16 dev_addr;
     63	int ret;
     64
     65	mdio_cfg = ENETC_EMDIO_CFG;
     66	if (regnum & MII_ADDR_C45) {
     67		dev_addr = (regnum >> 16) & 0x1f;
     68		mdio_cfg |= MDIO_CFG_ENC45;
     69	} else {
     70		/* clause 22 (ie 1G) */
     71		dev_addr = regnum & 0x1f;
     72		mdio_cfg &= ~MDIO_CFG_ENC45;
     73	}
     74
     75	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
     76
     77	ret = enetc_mdio_wait_complete(mdio_priv);
     78	if (ret)
     79		return ret;
     80
     81	/* set port and dev addr */
     82	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
     83	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
     84
     85	/* set the register address */
     86	if (regnum & MII_ADDR_C45) {
     87		enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
     88
     89		ret = enetc_mdio_wait_complete(mdio_priv);
     90		if (ret)
     91			return ret;
     92	}
     93
     94	/* write the value */
     95	enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value);
     96
     97	ret = enetc_mdio_wait_complete(mdio_priv);
     98	if (ret)
     99		return ret;
    100
    101	return 0;
    102}
    103EXPORT_SYMBOL_GPL(enetc_mdio_write);
    104
    105int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
    106{
    107	struct enetc_mdio_priv *mdio_priv = bus->priv;
    108	u32 mdio_ctl, mdio_cfg;
    109	u16 dev_addr, value;
    110	int ret;
    111
    112	mdio_cfg = ENETC_EMDIO_CFG;
    113	if (regnum & MII_ADDR_C45) {
    114		dev_addr = (regnum >> 16) & 0x1f;
    115		mdio_cfg |= MDIO_CFG_ENC45;
    116	} else {
    117		dev_addr = regnum & 0x1f;
    118		mdio_cfg &= ~MDIO_CFG_ENC45;
    119	}
    120
    121	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
    122
    123	ret = enetc_mdio_wait_complete(mdio_priv);
    124	if (ret)
    125		return ret;
    126
    127	/* set port and device addr */
    128	mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
    129	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
    130
    131	/* set the register address */
    132	if (regnum & MII_ADDR_C45) {
    133		enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
    134
    135		ret = enetc_mdio_wait_complete(mdio_priv);
    136		if (ret)
    137			return ret;
    138	}
    139
    140	/* initiate the read */
    141	enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
    142
    143	ret = enetc_mdio_wait_complete(mdio_priv);
    144	if (ret)
    145		return ret;
    146
    147	/* return all Fs if nothing was there */
    148	if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) {
    149		dev_dbg(&bus->dev,
    150			"Error while reading PHY%d reg at %d.%d\n",
    151			phy_id, dev_addr, regnum);
    152		return 0xffff;
    153	}
    154
    155	value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff;
    156
    157	return value;
    158}
    159EXPORT_SYMBOL_GPL(enetc_mdio_read);
    160
    161struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
    162{
    163	struct enetc_hw *hw;
    164
    165	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
    166	if (!hw)
    167		return ERR_PTR(-ENOMEM);
    168
    169	hw->port = port_regs;
    170
    171	return hw;
    172}
    173EXPORT_SYMBOL_GPL(enetc_hw_alloc);
    174
    175/* Lock for MDIO access errata on LS1028A */
    176DEFINE_RWLOCK(enetc_mdio_lock);
    177EXPORT_SYMBOL_GPL(enetc_mdio_lock);