phy: Add Sparx5 ethernet serdes PHY driver
Add the Microchip Sparx5 ethernet serdes PHY driver for the 6G, 10G and 25G interfaces available in the Sparx5 SoC. Signed-off-by: Bjarni Jonasson <bjarni.jonasson@microchip.com> Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Link: https://lore.kernel.org/r/20210218161451.3489955-4-steen.hegelund@microchip.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
6c172e7369
commit
2ff8a1eeb5
|
@ -71,6 +71,7 @@ source "drivers/phy/ingenic/Kconfig"
|
|||
source "drivers/phy/lantiq/Kconfig"
|
||||
source "drivers/phy/marvell/Kconfig"
|
||||
source "drivers/phy/mediatek/Kconfig"
|
||||
source "drivers/phy/microchip/Kconfig"
|
||||
source "drivers/phy/motorola/Kconfig"
|
||||
source "drivers/phy/mscc/Kconfig"
|
||||
source "drivers/phy/qualcomm/Kconfig"
|
||||
|
|
|
@ -20,6 +20,7 @@ obj-y += allwinner/ \
|
|||
lantiq/ \
|
||||
marvell/ \
|
||||
mediatek/ \
|
||||
microchip/ \
|
||||
motorola/ \
|
||||
mscc/ \
|
||||
qualcomm/ \
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Phy drivers for Microchip devices
|
||||
#
|
||||
|
||||
config PHY_SPARX5_SERDES
|
||||
tristate "Microchip Sparx5 SerDes PHY driver"
|
||||
select GENERIC_PHY
|
||||
depends on OF
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Enable this for support of the 10G/25G SerDes on Microchip Sparx5.
|
|
@ -0,0 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Makefile for the Microchip phy drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_PHY_SPARX5_SERDES) := sparx5_serdes.o
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,136 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+
|
||||
* Microchip Sparx5 SerDes driver
|
||||
*
|
||||
* Copyright (c) 2020 Microchip Technology Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SPARX5_SERDES_H_
|
||||
#define _SPARX5_SERDES_H_
|
||||
|
||||
#include "sparx5_serdes_regs.h"
|
||||
|
||||
#define SPX5_SERDES_MAX 33
|
||||
|
||||
enum sparx5_serdes_type {
|
||||
SPX5_SDT_6G = 6,
|
||||
SPX5_SDT_10G = 10,
|
||||
SPX5_SDT_25G = 25,
|
||||
};
|
||||
|
||||
enum sparx5_serdes_mode {
|
||||
SPX5_SD_MODE_NONE,
|
||||
SPX5_SD_MODE_2G5,
|
||||
SPX5_SD_MODE_QSGMII,
|
||||
SPX5_SD_MODE_100FX,
|
||||
SPX5_SD_MODE_1000BASEX,
|
||||
SPX5_SD_MODE_SFI,
|
||||
};
|
||||
|
||||
struct sparx5_serdes_private {
|
||||
struct device *dev;
|
||||
void __iomem *regs[NUM_TARGETS];
|
||||
struct phy *phys[SPX5_SERDES_MAX];
|
||||
bool cmu_enabled;
|
||||
unsigned long coreclock;
|
||||
};
|
||||
|
||||
struct sparx5_serdes_macro {
|
||||
struct sparx5_serdes_private *priv;
|
||||
u32 sidx;
|
||||
u32 stpidx;
|
||||
enum sparx5_serdes_type serdestype;
|
||||
enum sparx5_serdes_mode serdesmode;
|
||||
phy_interface_t portmode;
|
||||
int speed;
|
||||
enum phy_media media;
|
||||
};
|
||||
|
||||
/* Read, Write and modify registers content.
|
||||
* The register definition macros start at the id
|
||||
*/
|
||||
static inline void __iomem *sdx5_addr(void __iomem *base[],
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst,
|
||||
int gcnt, int gwidth,
|
||||
int raddr, int rinst,
|
||||
int rcnt, int rwidth)
|
||||
{
|
||||
WARN_ON((tinst) >= tcnt);
|
||||
WARN_ON((ginst) >= gcnt);
|
||||
WARN_ON((rinst) >= rcnt);
|
||||
return base[id + (tinst)] +
|
||||
gbase + ((ginst) * gwidth) +
|
||||
raddr + ((rinst) * rwidth);
|
||||
}
|
||||
|
||||
static inline void __iomem *sdx5_inst_baseaddr(void __iomem *base,
|
||||
int gbase, int ginst,
|
||||
int gcnt, int gwidth,
|
||||
int raddr, int rinst,
|
||||
int rcnt, int rwidth)
|
||||
{
|
||||
WARN_ON((ginst) >= gcnt);
|
||||
WARN_ON((rinst) >= rcnt);
|
||||
return base +
|
||||
gbase + ((ginst) * gwidth) +
|
||||
raddr + ((rinst) * rwidth);
|
||||
}
|
||||
|
||||
static inline void sdx5_rmw(u32 val, u32 mask, struct sparx5_serdes_private *priv,
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst, int gcnt, int gwidth,
|
||||
int raddr, int rinst, int rcnt, int rwidth)
|
||||
{
|
||||
u32 nval;
|
||||
void __iomem *addr =
|
||||
sdx5_addr(priv->regs, id, tinst, tcnt,
|
||||
gbase, ginst, gcnt, gwidth,
|
||||
raddr, rinst, rcnt, rwidth);
|
||||
nval = readl(addr);
|
||||
nval = (nval & ~mask) | (val & mask);
|
||||
writel(nval, addr);
|
||||
}
|
||||
|
||||
static inline void sdx5_inst_rmw(u32 val, u32 mask, void __iomem *iomem,
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase, int ginst, int gcnt, int gwidth,
|
||||
int raddr, int rinst, int rcnt, int rwidth)
|
||||
{
|
||||
u32 nval;
|
||||
void __iomem *addr =
|
||||
sdx5_inst_baseaddr(iomem,
|
||||
gbase, ginst, gcnt, gwidth,
|
||||
raddr, rinst, rcnt, rwidth);
|
||||
nval = readl(addr);
|
||||
nval = (nval & ~mask) | (val & mask);
|
||||
writel(nval, addr);
|
||||
}
|
||||
|
||||
static inline void sdx5_rmw_addr(u32 val, u32 mask, void __iomem *addr)
|
||||
{
|
||||
u32 nval;
|
||||
|
||||
nval = readl(addr);
|
||||
nval = (nval & ~mask) | (val & mask);
|
||||
writel(nval, addr);
|
||||
}
|
||||
|
||||
static inline void __iomem *sdx5_inst_get(struct sparx5_serdes_private *priv,
|
||||
int id, int tinst)
|
||||
{
|
||||
return priv->regs[id + tinst];
|
||||
}
|
||||
|
||||
static inline void __iomem *sdx5_inst_addr(void __iomem *iomem,
|
||||
int id, int tinst, int tcnt,
|
||||
int gbase,
|
||||
int ginst, int gcnt, int gwidth,
|
||||
int raddr,
|
||||
int rinst, int rcnt, int rwidth)
|
||||
{
|
||||
return sdx5_inst_baseaddr(iomem, gbase, ginst, gcnt, gwidth,
|
||||
raddr, rinst, rcnt, rwidth);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _SPARX5_SERDES_REGS_H_ */
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue