summaryrefslogtreecommitdiff
path: root/arch/arm/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/Makefile1
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/cpu.c4
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c110
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c117
4 files changed, 232 insertions, 0 deletions
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 <asm/arch-fsl-lsch3/immap_lsch3.h>
#include <fsl_debug_server.h>
#include <fsl-mc/fsl_mc.h>
+#include <asm/arch/fsl_serdes.h>
#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 <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch/fsl_serdes.h>
+#include <asm/arch-fsl-lsch3/immap_lsch3.h>
+
+#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 <common.h>
+#include <asm/arch/fsl_serdes.h>
+#include <asm/arch-fsl-lsch3/immap_lsch3.h>
+
+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;
+}