Add support for lan969x SERDES driver. Lan969x has ten 10G SERDES'es
which share the same features and data rates as the Sparx5 SERDES'es.
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Steen Hegelund <Steen.Hegelund@microchip.com>
---
drivers/phy/microchip/sparx5_serdes.c | 88 +++++++++++++++++++++++++++++++++++
drivers/phy/microchip/sparx5_serdes.h | 2 +
2 files changed, 90 insertions(+)
diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c
index 05fdf225ff43..320cf5b50a8c 100644
--- a/drivers/phy/microchip/sparx5_serdes.c
+++ b/drivers/phy/microchip/sparx5_serdes.c
@@ -25,6 +25,8 @@
#define SPX5_SERDES_25G_START 25
#define SPX5_SERDES_6G10G_CNT SPX5_SERDES_25G_START
+#define LAN969X_SERDES_10G_CNT 10
+
/* Optimal power settings from GUC */
#define SPX5_SERDES_QUIET_MODE_VAL 0x01ef4e0c
@@ -36,6 +38,13 @@ const unsigned int sparx5_serdes_tsize[TSIZE_LAST] = {
[TC_SD_LANE] = 25,
};
+const unsigned int lan969x_serdes_tsize[TSIZE_LAST] = {
+ [TC_SD10G_LANE] = 10,
+ [TC_SD_CMU] = 6,
+ [TC_SD_CMU_CFG] = 6,
+ [TC_SD_LANE] = 10,
+};
+
/* Pointer to the register target size table */
const unsigned int *tsize;
@@ -1096,6 +1105,24 @@ static int sparx5_serdes_cmu_get(enum sparx5_10g28cmu_mode mode, int sd_index)
return sparx5_serdes_cmu_map[mode][sd_index];
}
+/* Map of 6G/10G serdes mode and index to CMU index. */
+static const int
+lan969x_serdes_cmu_map[SPX5_SD10G28_CMU_MAX][LAN969X_SERDES_10G_CNT] = {
+ [SPX5_SD10G28_CMU_MAIN] = { 2, 2, 2, 2, 2,
+ 2, 2, 2, 5, 5 },
+ [SPX5_SD10G28_CMU_AUX1] = { 0, 0, 3, 3, 3,
+ 3, 3, 3, 3, 3 },
+ [SPX5_SD10G28_CMU_AUX2] = { 1, 1, 1, 1, 4,
+ 4, 4, 4, 4, 4 },
+ [SPX5_SD10G28_CMU_NONE] = { 1, 1, 1, 1, 4,
+ 4, 4, 4, 4, 4 },
+};
+
+static int lan969x_serdes_cmu_get(enum sparx5_10g28cmu_mode mode, int sd_index)
+{
+ return lan969x_serdes_cmu_map[mode][sd_index];
+}
+
static void sparx5_serdes_cmu_power_off(struct sparx5_serdes_private *priv)
{
void __iomem *cmu_inst, *cmu_cfg_inst;
@@ -2184,6 +2211,10 @@ static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro)
{
struct sparx5_serdes_private *priv = macro->priv;
+ /* Clock is auto-detected in 100Base-FX mode on lan969x */
+ if (priv->data->type == SPX5_TARGET_LAN969X)
+ return 0;
+
if (macro->serdesmode == SPX5_SD_MODE_100FX) {
u32 freq = priv->coreclock == 250000000 ? 2 :
priv->coreclock == 500000000 ? 1 : 0;
@@ -2395,6 +2426,12 @@ static void sparx5_serdes_type_set(struct sparx5_serdes_macro *macro, int sidx)
}
}
+static void lan969x_serdes_type_set(struct sparx5_serdes_macro *macro, int sidx)
+{
+ macro->serdestype = SPX5_SDT_10G;
+ macro->stpidx = macro->sidx;
+}
+
static int sparx5_phy_create(struct sparx5_serdes_private *priv,
int idx, struct phy **phy)
{
@@ -2519,6 +2556,41 @@ static struct sparx5_serdes_io_resource sparx5_serdes_iomap[] = {
{ TARGET_SD_LANE_25G + 7, 0x5c8000 }, /* 0x610dd0000: sd_lane_25g_32 */
};
+static const struct sparx5_serdes_io_resource lan969x_serdes_iomap[] = {
+ { TARGET_SD_CMU, 0x0 }, /* 0xe3410000 */
+ { TARGET_SD_CMU + 1, 0x8000 }, /* 0xe3418000 */
+ { TARGET_SD_CMU + 2, 0x10000 }, /* 0xe3420000 */
+ { TARGET_SD_CMU + 3, 0x18000 }, /* 0xe3428000 */
+ { TARGET_SD_CMU + 4, 0x20000 }, /* 0xe3430000 */
+ { TARGET_SD_CMU + 5, 0x28000 }, /* 0xe3438000 */
+ { TARGET_SD_CMU_CFG, 0x30000 }, /* 0xe3440000 */
+ { TARGET_SD_CMU_CFG + 1, 0x38000 }, /* 0xe3448000 */
+ { TARGET_SD_CMU_CFG + 2, 0x40000 }, /* 0xe3450000 */
+ { TARGET_SD_CMU_CFG + 3, 0x48000 }, /* 0xe3458000 */
+ { TARGET_SD_CMU_CFG + 4, 0x50000 }, /* 0xe3460000 */
+ { TARGET_SD_CMU_CFG + 5, 0x58000 }, /* 0xe3468000 */
+ { TARGET_SD10G_LANE, 0x60000 }, /* 0xe3470000 */
+ { TARGET_SD10G_LANE + 1, 0x68000 }, /* 0xe3478000 */
+ { TARGET_SD10G_LANE + 2, 0x70000 }, /* 0xe3480000 */
+ { TARGET_SD10G_LANE + 3, 0x78000 }, /* 0xe3488000 */
+ { TARGET_SD10G_LANE + 4, 0x80000 }, /* 0xe3490000 */
+ { TARGET_SD10G_LANE + 5, 0x88000 }, /* 0xe3498000 */
+ { TARGET_SD10G_LANE + 6, 0x90000 }, /* 0xe34a0000 */
+ { TARGET_SD10G_LANE + 7, 0x98000 }, /* 0xe34a8000 */
+ { TARGET_SD10G_LANE + 8, 0xa0000 }, /* 0xe34b0000 */
+ { TARGET_SD10G_LANE + 9, 0xa8000 }, /* 0xe34b8000 */
+ { TARGET_SD_LANE, 0x100000 }, /* 0xe3510000 */
+ { TARGET_SD_LANE + 1, 0x108000 }, /* 0xe3518000 */
+ { TARGET_SD_LANE + 2, 0x110000 }, /* 0xe3520000 */
+ { TARGET_SD_LANE + 3, 0x118000 }, /* 0xe3528000 */
+ { TARGET_SD_LANE + 4, 0x120000 }, /* 0xe3530000 */
+ { TARGET_SD_LANE + 5, 0x128000 }, /* 0xe3538000 */
+ { TARGET_SD_LANE + 6, 0x130000 }, /* 0xe3540000 */
+ { TARGET_SD_LANE + 7, 0x138000 }, /* 0xe3548000 */
+ { TARGET_SD_LANE + 8, 0x140000 }, /* 0xe3550000 */
+ { TARGET_SD_LANE + 9, 0x148000 }, /* 0xe3558000 */
+};
+
static const struct sparx5_serdes_match_data sparx5_desc = {
.type = SPX5_TARGET_SPARX5,
.iomap = sparx5_serdes_iomap,
@@ -2534,6 +2606,21 @@ static const struct sparx5_serdes_match_data sparx5_desc = {
},
};
+static const struct sparx5_serdes_match_data lan969x_desc = {
+ .type = SPX5_TARGET_LAN969X,
+ .iomap = lan969x_serdes_iomap,
+ .iomap_size = ARRAY_SIZE(lan969x_serdes_iomap),
+ .tsize = lan969x_serdes_tsize,
+ .consts = {
+ .sd_max = 10,
+ .cmu_max = 6,
+ },
+ .ops = {
+ .serdes_type_set = &lan969x_serdes_type_set,
+ .serdes_cmu_get = &lan969x_serdes_cmu_get,
+ }
+};
+
/* Client lookup function, uses serdes index */
static struct phy *sparx5_serdes_xlate(struct device *dev,
const struct of_phandle_args *args)
@@ -2635,6 +2722,7 @@ static int sparx5_serdes_probe(struct platform_device *pdev)
static const struct of_device_id sparx5_serdes_match[] = {
{ .compatible = "microchip,sparx5-serdes", .data = &sparx5_desc },
+ { .compatible = "microchip,lan9691-serdes", .data = &lan969x_desc },
{ }
};
MODULE_DEVICE_TABLE(of, sparx5_serdes_match);
diff --git a/drivers/phy/microchip/sparx5_serdes.h b/drivers/phy/microchip/sparx5_serdes.h
index 1beaa3d05a5d..d7093d0b09c0 100644
--- a/drivers/phy/microchip/sparx5_serdes.h
+++ b/drivers/phy/microchip/sparx5_serdes.h
@@ -36,6 +36,8 @@ enum sparx5_10g28cmu_mode {
enum sparx5_target {
SPX5_TARGET_SPARX5,
+ SPX5_TARGET_LAN969X,
+
};
struct sparx5_serdes_macro {
--
2.34.1