#include "phy-fsl-lynx-core.h"
#define LYNX_28G_NUM_LANE 8
-#define LYNX_28G_NUM_PLL 2
+#define LYNX_28G_NUM_PLL LYNX_NUM_PLL
/* SoC IP wrapper for protocol converters */
#define PCC8 0x10a0
/* Per PLL registers */
#define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
-#define PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
-#define PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
+#define PLLnRSTCTL_DIS BIT(24)
+#define PLLnRSTCTL_LOCK BIT(23)
#define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
#define PLLnCR0_REFCLK_SEL GENMASK(20, 16)
#define LYNX_28G_LANE_STOP_SLEEP_US 100
#define LYNX_28G_LANE_STOP_TIMEOUT_US 1000000
+#define lynx_28g_read lynx_read
+#define lynx_28g_write lynx_write
+#define lynx_28g_lane_rmw lynx_lane_rmw
+#define lynx_28g_lane_read lynx_lane_read
+#define lynx_28g_lane_write lynx_lane_write
+#define lynx_28g_pll_read lynx_pll_read
+
+#define lynx_28g_priv lynx_priv
+#define lynx_28g_lane lynx_lane
+#define lynx_28g_pll lynx_pll
+
enum lynx_28g_eq_type {
EQ_TYPE_NO_EQ = 0,
EQ_TYPE_2TAP = 1,
},
};
-struct lynx_28g_priv;
-
-struct lynx_28g_pll {
- struct lynx_28g_priv *priv;
- u32 rstctl, cr0, cr1;
- int id;
- DECLARE_BITMAP(supported, LANE_MODE_MAX);
-};
-
-struct lynx_28g_lane {
- struct lynx_28g_priv *priv;
- struct phy *phy;
- bool powered_up;
- bool init;
- unsigned int id;
- enum lynx_lane_mode mode;
-};
-
-struct lynx_28g_priv {
- void __iomem *base;
- struct device *dev;
- const struct lynx_info *info;
- /* Serialize concurrent access to registers shared between lanes,
- * like PCCn
- */
- spinlock_t pcc_lock;
- struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];
- struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];
-
- struct delayed_work cdr_check;
-};
-
-static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
- u32 val, u32 mask)
-{
- void __iomem *reg = priv->base + off;
- u32 orig, tmp;
-
- orig = ioread32(reg);
- tmp = orig & ~mask;
- tmp |= val;
- iowrite32(tmp, reg);
-}
-
-#define lynx_28g_read(priv, off) \
- ioread32((priv)->base + (off))
-#define lynx_28g_write(priv, off, val) \
- iowrite32(val, (priv)->base + (off))
-#define lynx_28g_lane_rmw(lane, reg, val, mask) \
- lynx_28g_rmw((lane)->priv, reg(lane->id), val, mask)
-#define lynx_28g_lane_read(lane, reg) \
- ioread32((lane)->priv->base + reg((lane)->id))
-#define lynx_28g_lane_write(lane, reg, val) \
- iowrite32(val, (lane)->priv->base + reg((lane)->id))
-#define lynx_28g_pll_read(pll, reg) \
- ioread32((pll)->priv->base + reg((pll)->id))
-
-/* A lane mode is supported if we have a PLL that can provide its required
- * clock net, and if there is a protocol converter for that mode on that lane.
- */
-static bool lynx_28g_supports_lane_mode(struct lynx_28g_lane *lane,
- enum lynx_lane_mode mode)
-{
- struct lynx_28g_priv *priv = lane->priv;
- int i;
-
- if (!priv->info->lane_supports_mode(lane->id, mode))
- return false;
-
- for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
- if (PLLnRSTCTL_DIS(priv->pll[i].rstctl))
- continue;
-
- if (test_bit(mode, priv->pll[i].supported))
- return true;
- }
-
- return false;
-}
-
static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
enum lynx_lane_mode mode)
{
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
pll = &priv->pll[i];
- if (PLLnRSTCTL_DIS(pll->rstctl))
+ if (!pll->enabled)
continue;
if (test_bit(mode, pll->supported))
}
/* no pll supports requested mode, either caller forgot to check
- * lynx_28g_supports_lane_mode, or this is a bug.
+ * lynx_lane_supports_mode(), or this is a bug.
*/
dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n",
lynx_lane_mode_str(mode));
struct lynx_28g_pll *pll,
enum lynx_lane_mode lane_mode)
{
- switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ switch (pll->frate_sel) {
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
switch (lane_mode) {
static const struct lynx_info lynx_info_compat = {
.lane_supports_mode = lynx_28g_compat_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2160a_serdes1 = {
.lane_supports_mode = lx2160a_serdes1_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2160a_serdes2 = {
.lane_supports_mode = lx2160a_serdes2_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2160a_serdes3 = {
.lane_supports_mode = lx2160a_serdes3_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2162a_serdes1 = {
.lane_supports_mode = lx2162a_serdes1_lane_supports_mode,
.first_lane = 4,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static const struct lynx_info lynx_info_lx2162a_serdes2 = {
.lane_supports_mode = lx2162a_serdes2_lane_supports_mode,
+ .num_lanes = LYNX_28G_NUM_LANE,
};
static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode,
return -EOPNOTSUPP;
lane_mode = phy_interface_to_lane_mode(submode);
- if (!lynx_28g_supports_lane_mode(lane, lane_mode))
+ if (!lynx_lane_supports_mode(lane, lane_mode))
return -EOPNOTSUPP;
if (lane_mode == lane->mode)
return -EOPNOTSUPP;
lane_mode = phy_interface_to_lane_mode(submode);
- if (!lynx_28g_supports_lane_mode(lane, lane_mode))
+ if (!lynx_lane_supports_mode(lane, lane_mode))
return -EOPNOTSUPP;
return 0;
static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
{
struct lynx_28g_pll *pll;
+ u32 val;
int i;
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
pll->priv = priv;
pll->id = i;
- pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);
- pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
- pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
+ val = lynx_28g_pll_read(pll, PLLnRSTCTL);
+ pll->enabled = !(val & PLLnRSTCTL_DIS);
+ pll->locked = !!(val & PLLnRSTCTL_LOCK);
- if (PLLnRSTCTL_DIS(pll->rstctl))
+ val = lynx_28g_pll_read(pll, PLLnCR0);
+ pll->refclk_sel = FIELD_GET(PLLnCR0_REFCLK_SEL, val);
+
+ val = lynx_28g_pll_read(pll, PLLnCR1);
+ pll->frate_sel = FIELD_GET(PLLnCR1_FRATE_SEL, val);
+
+ if (!pll->enabled)
continue;
- switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ switch (pll->frate_sel) {
case PLLnCR1_FRATE_5G_10GVCO:
case PLLnCR1_FRATE_5G_25GVCO:
/* 5GHz clock net */
if (priv->info == &lynx_info_compat)
dev_warn(dev, "Please update device tree to use per-device compatible strings\n");
+ priv->lane = devm_kcalloc(dev, priv->info->num_lanes,
+ sizeof(*priv->lane), GFP_KERNEL);
+ if (!priv->lane)
+ return -ENOMEM;
+
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
#include <linux/phy.h>
#include <soc/fsl/phy-fsl-lynx.h>
+#define LYNX_NUM_PLL 2
+
struct lynx_pccr {
int offset;
int width;
int shift;
};
+struct lynx_priv;
+
+struct lynx_pll {
+ struct lynx_priv *priv;
+ int id;
+ int refclk_sel;
+ int frate_sel;
+ bool enabled;
+ bool locked;
+ DECLARE_BITMAP(supported, LANE_MODE_MAX);
+};
+
+struct lynx_lane {
+ struct lynx_priv *priv;
+ struct phy *phy;
+ bool powered_up;
+ bool init;
+ unsigned int id;
+ enum lynx_lane_mode mode;
+};
+
struct lynx_info {
bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
int first_lane;
+ int num_lanes;
};
+struct lynx_priv {
+ void __iomem *base;
+ struct device *dev;
+ const struct lynx_info *info;
+ /* Serialize concurrent access to registers shared between lanes,
+ * like PCCn
+ */
+ spinlock_t pcc_lock;
+ struct lynx_pll pll[LYNX_NUM_PLL];
+ struct lynx_lane *lane;
+
+ struct delayed_work cdr_check;
+};
+
+static inline void lynx_rmw(struct lynx_priv *priv, unsigned long off, u32 val,
+ u32 mask)
+{
+ void __iomem *reg = priv->base + off;
+ u32 orig, tmp;
+
+ orig = ioread32(reg);
+ tmp = orig & ~mask;
+ tmp |= val;
+ iowrite32(tmp, reg);
+}
+
+#define lynx_read(priv, off) \
+ ioread32((priv)->base + (off))
+#define lynx_write(priv, off, val) \
+ iowrite32(val, (priv)->base + (off))
+#define lynx_lane_rmw(lane, reg, val, mask) \
+ lynx_rmw((lane)->priv, reg(lane->id), val, mask)
+#define lynx_lane_read(lane, reg) \
+ ioread32((lane)->priv->base + reg((lane)->id))
+#define lynx_lane_write(lane, reg, val) \
+ iowrite32(val, (lane)->priv->base + reg((lane)->id))
+#define lynx_pll_read(pll, reg) \
+ ioread32((pll)->priv->base + reg((pll)->id))
+
const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode);
enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf);
+bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode);
#endif