diff options
-rw-r--r-- | arch/arm/include/asm/ti-common/keystone_serdes.h | 42 | ||||
-rw-r--r-- | drivers/net/keystone_net.c | 15 | ||||
-rw-r--r-- | drivers/soc/keystone/keystone_serdes.c | 131 | ||||
-rw-r--r-- | include/configs/ks2_evm.h | 10 |
4 files changed, 156 insertions, 42 deletions
diff --git a/arch/arm/include/asm/ti-common/keystone_serdes.h b/arch/arm/include/asm/ti-common/keystone_serdes.h index 2e12b05..2e92411 100644 --- a/arch/arm/include/asm/ti-common/keystone_serdes.h +++ b/arch/arm/include/asm/ti-common/keystone_serdes.h @@ -10,6 +10,46 @@ #ifndef __TI_KEYSTONE_SERDES_H__ #define __TI_KEYSTONE_SERDES_H__ -void ks2_serdes_sgmii_156p25mhz_setup(void); +/* SERDES Reference clock */ +enum ks2_serdes_clock { + SERDES_CLOCK_100M, /* 100 MHz */ + SERDES_CLOCK_122P88M, /* 122.88 MHz */ + SERDES_CLOCK_125M, /* 125 MHz */ + SERDES_CLOCK_156P25M, /* 156.25 MHz */ + SERDES_CLOCK_312P5M, /* 312.5 MHz */ +}; + +/* SERDES Lane Baud Rate */ +enum ks2_serdes_rate { + SERDES_RATE_4P9152G, /* 4.9152 GBaud */ + SERDES_RATE_5G, /* 5 GBaud */ + SERDES_RATE_6P144G, /* 6.144 GBaud */ + SERDES_RATE_6P25G, /* 6.25 GBaud */ + SERDES_RATE_10p3125g, /* 10.3215 GBaud */ + SERDES_RATE_12p5g, /* 12.5 GBaud */ +}; + +/* SERDES Lane Rate Mode */ +enum ks2_serdes_rate_mode { + SERDES_FULL_RATE, + SERDES_HALF_RATE, + SERDES_QUARTER_RATE, +}; + +/* SERDES PHY TYPE */ +enum ks2_serdes_interface { + SERDES_PHY_SGMII, + SERDES_PHY_PCSR, /* XGE SERDES */ +}; + +struct ks2_serdes { + enum ks2_serdes_clock clk; + enum ks2_serdes_rate rate; + enum ks2_serdes_rate_mode rate_mode; + enum ks2_serdes_interface intf; + u32 loopback; +}; + +int ks2_serdes_init(u32 base, struct ks2_serdes *serdes, u32 num_lanes); #endif /* __TI_KEYSTONE_SERDES_H__ */ diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index 63f3361..8a45fbd 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -554,7 +554,20 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) return 0; } +struct ks2_serdes ks2_serdes_sgmii_156p25mhz = { + .clk = SERDES_CLOCK_156P25M, + .rate = SERDES_RATE_5G, + .rate_mode = SERDES_QUARTER_RATE, + .intf = SERDES_PHY_SGMII, + .loopback = 0, +}; + static void keystone2_net_serdes_setup(void) { - ks2_serdes_sgmii_156p25mhz_setup(); + ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE, + &ks2_serdes_sgmii_156p25mhz, + CONFIG_KSNET_SERDES_LANES_PER_SGMII); + + /* wait till setup */ + udelay(5000); } diff --git a/drivers/soc/keystone/keystone_serdes.c b/drivers/soc/keystone/keystone_serdes.c index 3632c22..84ed9ba 100644 --- a/drivers/soc/keystone/keystone_serdes.c +++ b/drivers/soc/keystone/keystone_serdes.c @@ -7,9 +7,27 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#include <errno.h> #include <common.h> +#include <asm/ti-common/keystone_serdes.h> +#define SERDES_CMU_REGS(x) (0x0000 + (0x0c00 * (x))) #define SERDES_LANE_REGS(x) (0x0200 + (0x200 * (x))) +#define SERDES_COMLANE_REGS 0x0a00 +#define SERDES_WIZ_REGS 0x1fc0 + +#define SERDES_CMU_REG_000(x) (SERDES_CMU_REGS(x) + 0x000) +#define SERDES_CMU_REG_010(x) (SERDES_CMU_REGS(x) + 0x010) +#define SERDES_COMLANE_REG_000 (SERDES_COMLANE_REGS + 0x000) +#define SERDES_LANE_REG_000(x) (SERDES_LANE_REGS(x) + 0x000) +#define SERDES_LANE_REG_028(x) (SERDES_LANE_REGS(x) + 0x028) +#define SERDES_LANE_CTL_STATUS_REG(x) (SERDES_WIZ_REGS + 0x0020 + (4 * (x))) +#define SERDES_PLL_CTL_REG (SERDES_WIZ_REGS + 0x0034) + +#define SERDES_RESET BIT(28) +#define SERDES_LANE_RESET BIT(29) +#define SERDES_LANE_LOOPBACK BIT(30) +#define SERDES_LANE_EN_VAL(x, y, z) (x[y] | (z << 26) | (z << 10)) struct serdes_cfg { u32 ofs; @@ -17,6 +35,18 @@ struct serdes_cfg { u32 mask; }; +/* SERDES PHY lane enable configuration value, indexed by PHY interface */ +static u32 serdes_cfg_lane_enable[] = { + 0xf000f0c0, /* SGMII */ + 0xf0e9f038, /* PCSR */ +}; + +/* SERDES PHY PLL enable configuration value, indexed by PHY interface */ +static u32 serdes_cfg_pll_enable[] = { + 0xe0000000, /* SGMII */ + 0xee000000, /* PCSR */ +}; + static struct serdes_cfg cfg_cmu_156p25m_5g[] = { {0x0000, 0x00800000, 0xffff0000}, {0x0014, 0x00008282, 0x0000ffff}, @@ -91,39 +121,72 @@ static int ks2_serdes_init_156p25m_5g(u32 base, u32 num_lanes) return 0; } -void ks2_serdes_sgmii_156p25mhz_setup(void) +static void ks2_serdes_cmu_comlane_enable(u32 base, struct ks2_serdes *serdes) +{ + /* Bring SerDes out of Reset */ + ks2_serdes_rmw(base + SERDES_CMU_REG_010(0), 0x0, SERDES_RESET); + if (serdes->intf == SERDES_PHY_PCSR) + ks2_serdes_rmw(base + SERDES_CMU_REG_010(1), 0x0, SERDES_RESET); + + /* Enable CMU and COMLANE */ + ks2_serdes_rmw(base + SERDES_CMU_REG_000(0), 0x03, 0x000000ff); + if (serdes->intf == SERDES_PHY_PCSR) + ks2_serdes_rmw(base + SERDES_CMU_REG_000(1), 0x03, 0x000000ff); + + ks2_serdes_rmw(base + SERDES_COMLANE_REG_000, 0x5f, 0x000000ff); +} + +static void ks2_serdes_pll_enable(u32 base, struct ks2_serdes *serdes) +{ + writel(serdes_cfg_pll_enable[serdes->intf], + base + SERDES_PLL_CTL_REG); +} + +static void ks2_serdes_lane_reset(u32 base, u32 reset, u32 lane) { - unsigned int cnt; - - ks2_serdes_init_156p25m_5g(CONFIG_KS2_SERDES_SGMII_BASE, - CONFIG_KS2_SERDES_LANES_PER_SGMII); - - /*Bring SerDes out of Reset if SerDes is Shutdown & is in Reset Mode*/ - clrbits_le32(0x0232a010, 1 << 28); - - /* Enable TX and RX via the LANExCTL_STS 0x0000 + x*4 */ - clrbits_le32(0x0232a228, 1 << 29); - writel(0xF800F8C0, 0x0232bfe0); - clrbits_le32(0x0232a428, 1 << 29); - writel(0xF800F8C0, 0x0232bfe4); - clrbits_le32(0x0232a628, 1 << 29); - writel(0xF800F8C0, 0x0232bfe8); - clrbits_le32(0x0232a828, 1 << 29); - writel(0xF800F8C0, 0x0232bfec); - - /*Enable pll via the pll_ctrl 0x0014*/ - writel(0xe0000000, 0x0232bff4) - ; - - /*Waiting for SGMII Serdes PLL lock.*/ - for (cnt = 10000; cnt > 0 && ((readl(0x02090114) & 0x10) == 0); cnt--) - ; - for (cnt = 10000; cnt > 0 && ((readl(0x02090214) & 0x10) == 0); cnt--) - ; - for (cnt = 10000; cnt > 0 && ((readl(0x02090414) & 0x10) == 0); cnt--) - ; - for (cnt = 10000; cnt > 0 && ((readl(0x02090514) & 0x10) == 0); cnt--) - ; - - udelay(45000); + if (reset) + ks2_serdes_rmw(base + SERDES_LANE_REG_028(lane), + 0x1, SERDES_LANE_RESET); + else + ks2_serdes_rmw(base + SERDES_LANE_REG_028(lane), + 0x0, SERDES_LANE_RESET); +} + +static void ks2_serdes_lane_enable(u32 base, + struct ks2_serdes *serdes, u32 lane) +{ + /* Bring lane out of reset */ + ks2_serdes_lane_reset(base, 0, lane); + + writel(SERDES_LANE_EN_VAL(serdes_cfg_lane_enable, serdes->intf, + serdes->rate_mode), + base + SERDES_LANE_CTL_STATUS_REG(lane)); + + /* Set NES bit if Loopback Enabled */ + if (serdes->loopback) + ks2_serdes_rmw(base + SERDES_LANE_REG_000(lane), + 0x1, SERDES_LANE_LOOPBACK); +} + +int ks2_serdes_init(u32 base, struct ks2_serdes *serdes, u32 num_lanes) +{ + int i; + int ret = 0; + + /* The driver currently supports 5GBaud rate with ref clock 156.25MHz */ + if (serdes->clk == SERDES_CLOCK_156P25M) + if (serdes->rate == SERDES_RATE_5G) + ret = ks2_serdes_init_156p25m_5g(base, num_lanes); + else + return -EINVAL; + else + return -EINVAL; + + ks2_serdes_cmu_comlane_enable(base, serdes); + for (i = 0; i < num_lanes; i++) + ks2_serdes_lane_enable(base, serdes, i); + + ks2_serdes_pll_enable(base, serdes); + + return ret; } diff --git a/include/configs/ks2_evm.h b/include/configs/ks2_evm.h index 8037c3e..5ba975c 100644 --- a/include/configs/ks2_evm.h +++ b/include/configs/ks2_evm.h @@ -134,8 +134,10 @@ #define CONFIG_KSNAV_NETCP_PDMA_TX_SND_QUEUE KS2_NETCP_PDMA_TX_SND_QUEUE /* Keystone net */ -#define CONFIG_KSNET_MAC_ID_BASE KS2_MAC_ID_BASE_ADDR -#define CONFIG_KSNET_NETCP_BASE KS2_NETCP_BASE +#define CONFIG_KSNET_MAC_ID_BASE KS2_MAC_ID_BASE_ADDR +#define CONFIG_KSNET_NETCP_BASE KS2_NETCP_BASE +#define CONFIG_KSNET_SERDES_SGMII_BASE KS2_SGMII_SERDES_BASE +#define CONFIG_KSNET_SERDES_LANES_PER_SGMII KS2_LANES_PER_SGMII_SERDES /* AEMIF */ #define CONFIG_TI_AEMIF @@ -319,8 +321,4 @@ which is NOT applicable for DDR ECC test */ #define CONFIG_MAX_UBOOT_MEM_SIZE (4 << 20) /* 4 MiB */ -/* SGMII SerDes */ -#define CONFIG_KS2_SERDES_SGMII_BASE KS2_SGMII_SERDES_BASE -#define CONFIG_KS2_SERDES_LANES_PER_SGMII KS2_LANES_PER_SGMII_SERDES - #endif /* __CONFIG_KS2_EVM_H */ |