From 31d34c6c4b4470b4cd2094693259fb48ec51e652 Mon Sep 17 00:00:00 2001 From: Minghuan Lian Date: Fri, 20 Mar 2015 19:28:16 -0700 Subject: armv8: Add SerDes framework for Layerscape Architecture Add support of SerDes framework for Layerscape Architecture. - Add support of 2 SerDes block - Add SerDes protocol parsing and detection - Create table of SerDes protocol supported by LS2085A Signed-off-by: Prabhakar Kushwaha Signed-off-by: Minghuan Lian Reviewed-by: York Sun --- arch/arm/cpu/armv8/fsl-lsch3/Makefile | 1 + arch/arm/cpu/armv8/fsl-lsch3/cpu.c | 4 + arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c | 110 ++++++++++++++++++++++ arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c | 117 ++++++++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c create mode 100644 arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c (limited to 'arch/arm/cpu/armv8/fsl-lsch3') diff --git a/arch/arm/cpu/armv8/fsl-lsch3/Makefile b/arch/arm/cpu/armv8/fsl-lsch3/Makefile index 65425904c1..9f7815bd52 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/Makefile +++ b/arch/arm/cpu/armv8/fsl-lsch3/Makefile @@ -8,5 +8,6 @@ obj-y += cpu.o obj-y += lowlevel.o obj-y += soc.o obj-y += speed.o +obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch3_serdes.o ls2085a_serdes.o obj-$(CONFIG_MP) += mp.o obj-$(CONFIG_OF_LIBFDT) += fdt.o diff --git a/arch/arm/cpu/armv8/fsl-lsch3/cpu.c b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c index 595dbd1d63..caa48f2c3d 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/cpu.c +++ b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "cpu.h" #include "mp.h" #include "speed.h" @@ -415,6 +416,9 @@ int arch_early_init_r(void) if (rv) printf("Did not wake secondary cores\n"); +#ifdef CONFIG_SYS_HAS_SERDES + fsl_serdes_init(); +#endif return 0; } diff --git a/arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c b/arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c new file mode 100644 index 0000000000..78b92102c9 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c @@ -0,0 +1,110 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_SYS_FSL_SRDS_1 +static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT]; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 +static u8 serdes2_prtcl_map[SERDES_PRCTL_COUNT]; +#endif + +int is_serdes_configured(enum srds_prtcl device) +{ + int ret = 0; + +#ifdef CONFIG_SYS_FSL_SRDS_1 + ret |= serdes1_prtcl_map[device]; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + ret |= serdes2_prtcl_map[device]; +#endif + + return !!ret; +} + +int serdes_get_first_lane(u32 sd, enum srds_prtcl device) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg = in_le32(&gur->rcwsr[28]); + int i; + + switch (sd) { +#ifdef CONFIG_SYS_FSL_SRDS_1 + case FSL_SRDS_1: + cfg &= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK; + cfg >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT; + break; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + case FSL_SRDS_2: + cfg &= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK; + cfg >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT; + break; +#endif + default: + printf("invalid SerDes%d\n", sd); + break; + } + /* Is serdes enabled at all? */ + if (cfg == 0) + return -ENODEV; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (serdes_get_prtcl(sd, cfg, i) == device) + return i; + } + + return -ENODEV; +} + +void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift, + u8 serdes_prtcl_map[SERDES_PRCTL_COUNT]) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg; + int lane; + + memset(serdes_prtcl_map, 0, sizeof(serdes_prtcl_map)); + + cfg = in_le32(&gur->rcwsr[28]) & sd_prctl_mask; + cfg >>= sd_prctl_shift; + printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg); + + if (!is_serdes_prtcl_valid(sd, cfg)) + printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg); + + for (lane = 0; lane < SRDS_MAX_LANES; lane++) { + enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane); + if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT)) + debug("Unknown SerDes lane protocol %d\n", lane_prtcl); + else + serdes_prtcl_map[lane_prtcl] = 1; + } +} + +void fsl_serdes_init(void) +{ +#ifdef CONFIG_SYS_FSL_SRDS_1 + serdes_init(FSL_SRDS_1, + CONFIG_SYS_FSL_LSCH3_SERDES_ADDR, + FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK, + FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT, + serdes1_prtcl_map); +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + serdes_init(FSL_SRDS_2, + CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + FSL_SRDS_2 * 0x10000, + FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK, + FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT, + serdes2_prtcl_map); +#endif +} diff --git a/arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c b/arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c new file mode 100644 index 0000000000..098745bd74 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c @@ -0,0 +1,117 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +struct serdes_config { + u8 protocol; + u8 lanes[SRDS_MAX_LANES]; +}; + +static struct serdes_config serdes1_cfg_tbl[] = { + /* SerDes 1 */ + {0x03, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2 } }, + {0x05, {PCIE2, PCIE2, PCIE2, PCIE2, SGMII4, SGMII3, SGMII2, SGMII1 } }, + {0x07, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x09, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0A, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0C, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0E, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x26, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, XFI2, XFI1 } }, + {0x28, {SGMII8, SGMII7, SGMII6, SGMII5, XFI4, XFI3, XFI2, XFI1 } }, + {0x2A, {XFI8, XFI7, XFI6, XFI5, XFI4, XFI3, XFI2, XFI1 } }, + {0x2B, {SGMII8, SGMII7, SGMII6, SGMII5, XAUI1, XAUI1, XAUI1, XAUI1 } }, + {0x32, {XAUI2, XAUI2, XAUI2, XAUI2, XAUI1, XAUI1, XAUI1, XAUI1 } }, + {0x33, {PCIE2, PCIE2, PCIE2, PCIE2, QSGMII_D, QSGMII_C, QSGMII_B, + QSGMII_A} }, + {0x35, {QSGMII_D, QSGMII_C, QSGMII_B, PCIE2, XFI4, XFI3, XFI2, XFI1 } }, + {} +}; +static struct serdes_config serdes2_cfg_tbl[] = { + /* SerDes 2 */ + {0x07, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x09, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0A, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0C, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0E, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x3D, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3 } }, + {0x3E, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3 } }, + {0x3F, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } }, + {0x40, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } }, + {0x41, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2 } }, + {0x42, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2 } }, + {0x43, {PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE, SATA1, SATA2 } }, + {0x44, {PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE, SATA1, SATA2 } }, + {0x45, {PCIE3, SGMII10, SGMII11, SGMII12, PCIE4, SGMII14, SGMII15, + SGMII16 } }, + {0x47, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, PCIE4, + PCIE4 } }, + {0x49, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1, + SATA2 } }, + {0x4A, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1, + SATA2 } }, + {} +}; + +static struct serdes_config *serdes_cfg_tbl[] = { + serdes1_cfg_tbl, + serdes2_cfg_tbl, +}; + +enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane) +{ + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == cfg) + return ptr->lanes[lane]; + ptr++; + } + + return 0; +} + +int is_serdes_prtcl_valid(int serdes, u32 prtcl) +{ + int i; + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == prtcl) + break; + ptr++; + } + + if (!ptr->protocol) + return 0; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (ptr->lanes[i] != NONE) + return 1; + } + + return 0; +} -- cgit v1.2.1