armv8/fsl_lsch2: Add fsl_lsch2 SoC

Freescale LayerScape with Chassis Generation 2 is a set of SoCs with
ARMv8 cores and 2rd generation of Chassis.

Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Hou Zhiqiang <B48286@freescale.com>
Signed-off-by: Mingkai Hu <Mingkai.Hu@freescale.com>
Signed-off-by: Gong Qianyu <Qianyu.Gong@freescale.com>
Reviewed-by: York Sun <yorksun@freescale.com>
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Makefile b/arch/arm/cpu/armv8/fsl-layerscape/Makefile
index ccb3aa5..4754e59 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/Makefile
+++ b/arch/arm/cpu/armv8/fsl-layerscape/Makefile
@@ -14,6 +14,11 @@
 ifneq ($(CONFIG_FSL_LSCH3),)
 obj-y += fsl_lsch3_speed.o
 obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch3_serdes.o
+else
+ifneq ($(CONFIG_FSL_LSCH2),)
+obj-y += fsl_lsch2_speed.o
+obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch2_serdes.o
+endif
 endif
 
 ifneq ($(CONFIG_LS2085A),)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/README.lsch2 b/arch/arm/cpu/armv8/fsl-layerscape/README.lsch2
new file mode 100644
index 0000000..a6ef830
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-layerscape/README.lsch2
@@ -0,0 +1,10 @@
+#
+# Copyright 2015 Freescale Semiconductor
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+Freescale LayerScape with Chassis Generation 2
+
+This architecture supports Freescale ARMv8 SoCs with Chassis generation 2,
+for example LS1043A.
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
index be7442d..fe9d982 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
@@ -180,6 +180,8 @@
 	set_pgtable_table(level1_table0,
 			  CONFIG_SYS_FLASH_BASE >> SECTION_SHIFT_L1,
 			  level2_table1);
+#elif defined(CONFIG_FSL_LSCH2)
+	set_pgtable_table(level1_table0, 1, level2_table1);
 #endif
 	/* Find the table and fill in the block entries */
 	for (i = 0; i < ARRAY_SIZE(early_mmu_table); i++) {
@@ -215,6 +217,9 @@
  *
  * For LSCH3:
  * Level 2 table 1 contains 512 entries for each 2MB from 32GB to 33GB.
+ * For LSCH2:
+ * Level 2 table 1 contains 512 entries for each 2MB from 1GB to 2GB.
+ * Level 2 table 2 contains 512 entries for each 2MB from 20GB to 21GB.
  */
 static inline void final_mmu_setup(void)
 {
@@ -225,6 +230,9 @@
 	u64 *level2_table0 = (u64 *)(gd->arch.tlb_addr + 0x3000);
 #ifdef CONFIG_FSL_LSCH3
 	u64 *level2_table1 = (u64 *)(gd->arch.tlb_addr + 0x4000);
+#elif defined(CONFIG_FSL_LSCH2)
+	u64 *level2_table1 = (u64 *)(gd->arch.tlb_addr + 0x4000);
+	u64 *level2_table2 = (u64 *)(gd->arch.tlb_addr + 0x5000);
 #endif
 	struct table_info table = {level0_table, 0, BLOCK_SIZE_L0};
 
@@ -239,6 +247,11 @@
 	set_pgtable_table(level1_table0,
 			  CONFIG_SYS_FSL_QBMAN_BASE >> SECTION_SHIFT_L1,
 			  level2_table1);
+#elif defined(CONFIG_FSL_LSCH2)
+	set_pgtable_table(level1_table0, 1, level2_table1);
+	set_pgtable_table(level1_table0,
+			  CONFIG_SYS_FSL_QBMAN_BASE >> SECTION_SHIFT_L1,
+			  level2_table2);
 #endif
 
 	/* Find the table and fill in the block entries */
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c
new file mode 100644
index 0000000..f7178d1
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c
@@ -0,0 +1,117 @@
+/*
+ * 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/soc.h>
+
+#ifdef CONFIG_SYS_FSL_SRDS_1
+static u8 serdes1_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
+
+	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 = gur_in32(&gur->rcwsr[4]);
+	int i;
+
+	switch (sd) {
+#ifdef CONFIG_SYS_FSL_SRDS_1
+	case FSL_SRDS_1:
+		cfg &= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
+		cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
+		break;
+#endif
+	default:
+		printf("invalid SerDes%d\n", sd);
+		break;
+	}
+
+	/* Is serdes enabled at all? */
+	if (unlikely(cfg == 0))
+		return -ENODEV;
+
+	for (i = 0; i < SRDS_MAX_LANES; i++) {
+		if (serdes_get_prtcl(sd, cfg, i) == device)
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+int get_serdes_protocol(void)
+{
+	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+	u32 cfg = gur_in32(&gur->rcwsr[4]) &
+			  FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
+	cfg >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
+
+	return cfg;
+}
+
+const char *serdes_clock_to_string(u32 clock)
+{
+	switch (clock) {
+	case SRDS_PLLCR0_RFCK_SEL_100:
+		return "100";
+	case SRDS_PLLCR0_RFCK_SEL_125:
+		return "125";
+	case SRDS_PLLCR0_RFCK_SEL_156_25:
+		return "156.25";
+	default:
+		return "100";
+	}
+}
+
+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 = gur_in32(&gur->rcwsr[4]) & 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_SERDES_ADDR,
+		    FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK,
+		    FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT,
+		    serdes1_prtcl_map);
+#endif
+}
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c
new file mode 100644
index 0000000..ea3723f
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_speed.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compiler.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/soc.h>
+#include <fsl_ifc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_FSL_NUM_CC_PLLS
+#define CONFIG_SYS_FSL_NUM_CC_PLLS      2
+#endif
+
+void get_sys_info(struct sys_info *sys_info)
+{
+	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+#ifdef CONFIG_FSL_IFC
+	struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL};
+	u32 ccr;
+#endif
+	struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_CLK_ADDR);
+	unsigned int cpu;
+	const u8 core_cplx_pll[8] = {
+		[0] = 0,	/* CC1 PPL / 1 */
+		[1] = 0,	/* CC1 PPL / 2 */
+		[4] = 1,	/* CC2 PPL / 1 */
+		[5] = 1,	/* CC2 PPL / 2 */
+	};
+
+	const u8 core_cplx_pll_div[8] = {
+		[0] = 1,	/* CC1 PPL / 1 */
+		[1] = 2,	/* CC1 PPL / 2 */
+		[4] = 1,	/* CC2 PPL / 1 */
+		[5] = 2,	/* CC2 PPL / 2 */
+	};
+
+	uint i;
+	uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS];
+	uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS];
+	unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
+
+	sys_info->freq_systembus = sysclk;
+#ifdef CONFIG_DDR_CLK_FREQ
+	sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
+#else
+	sys_info->freq_ddrbus = sysclk;
+#endif
+
+	sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >>
+			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_SHIFT) &
+			FSL_CHASSIS2_RCWSR0_SYS_PLL_RAT_MASK;
+	sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >>
+			FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_SHIFT) &
+			FSL_CHASSIS2_RCWSR0_MEM_PLL_RAT_MASK;
+
+	for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) {
+		ratio[i] = (in_be32(&clk->pllcgsr[i].pllcngsr) >> 1) & 0xff;
+		if (ratio[i] > 4)
+			freq_c_pll[i] = sysclk * ratio[i];
+		else
+			freq_c_pll[i] = sys_info->freq_systembus * ratio[i];
+	}
+
+	for (cpu = 0; cpu < CONFIG_MAX_CPUS; cpu++) {
+		u32 c_pll_sel = (in_be32(&clk->clkcsr[cpu].clkcncsr) >> 27)
+				& 0xf;
+		u32 cplx_pll = core_cplx_pll[c_pll_sel];
+
+		sys_info->freq_processor[cpu] =
+			freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel];
+	}
+
+#define HWA_CGA_M1_CLK_SEL	0xe0000000
+#define HWA_CGA_M1_CLK_SHIFT	29
+
+#define HWA_CGA_M2_CLK_SEL	0x00000007
+#define HWA_CGA_M2_CLK_SHIFT	0
+
+#if defined(CONFIG_FSL_IFC)
+	ccr = ifc_in32(&ifc_regs.gregs->ifc_ccr);
+	ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1;
+
+	sys_info->freq_localbus = sys_info->freq_systembus / ccr;
+#endif
+}
+
+int get_clocks(void)
+{
+	struct sys_info sys_info;
+
+	get_sys_info(&sys_info);
+	gd->cpu_clk = sys_info.freq_processor[0];
+	gd->bus_clk = sys_info.freq_systembus;
+	gd->mem_clk = sys_info.freq_ddrbus;
+
+	if (gd->cpu_clk != 0)
+		return 0;
+	else
+		return 1;
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	return gd->mem_clk;
+}
+
+int get_serial_clock(void)
+{
+	return gd->bus_clk;
+}
+
+unsigned int mxc_get_clock(enum mxc_clock clk)
+{
+	switch (clk) {
+	case MXC_I2C_CLK:
+		return get_bus_freq(0);
+	case MXC_DSPI_CLK:
+		return get_bus_freq(0);
+	case MXC_UART_CLK:
+		return get_bus_freq(0);
+	default:
+		printf("Unsupported clock\n");
+	}
+	return 0;
+}
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
index 73e48a7..637853d 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
@@ -76,6 +76,23 @@
 	init_early_memctl_regs();	/* tighten IFC timing */
 	erratum_a009203();
 }
+
+#elif defined(CONFIG_LS1043A)
+void fsl_lsch2_early_init_f(void)
+{
+	struct ccsr_cci400 *cci = (struct ccsr_cci400 *)CONFIG_SYS_CCI400_ADDR;
+
+#ifdef CONFIG_FSL_IFC
+	init_early_memctl_regs();	/* tighten IFC timing */
+#endif
+
+	/*
+	 * Enable snoop requests and DVM message requests for
+	 * Slave insterface S4 (A53 core cluster)
+	 */
+	out_le32(&cci->slave[4].snoop_ctrl,
+		 CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN);
+}
 #endif
 
 #ifdef CONFIG_BOARD_LATE_INIT