mpc85xx: Add support for the MPC8536

The MPC8536 Adds SDHC and SATA controllers to the PQ3 family.  We
also have SERDES init code for the 8536.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
Signed-off-by: Dejan Minic <minic@freescale.com>
Signed-off-by: Jason Jin <Jason.jin@freescale.com>
Signed-off-by: Dave Liu <daveliu@freescale.com>
diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile
index 80b80ff..627e61b 100644
--- a/cpu/mpc85xx/Makefile
+++ b/cpu/mpc85xx/Makefile
@@ -49,6 +49,7 @@
 COBJS-$(CONFIG_MPC8572) += ddr-gen3.o
 COBJS-$(CONFIG_MPC8536) += ddr-gen3.o
 
+COBJS-$(CONFIG_MPC8536) += mpc8536_serdes.o
 COBJS	= traps.o cpu.o cpu_init.o speed.o interrupts.o tlb.o \
 	  pci.o serial_scc.o commproc.o ether_fcc.o qe_io.o \
 	  $(COBJS-y)
diff --git a/cpu/mpc85xx/cpu.c b/cpu/mpc85xx/cpu.c
index 5c2231d..2fe3cea 100644
--- a/cpu/mpc85xx/cpu.c
+++ b/cpu/mpc85xx/cpu.c
@@ -36,6 +36,8 @@
 struct cpu_type cpu_type_list [] = {
 	CPU_TYPE_ENTRY(8533, 8533),
 	CPU_TYPE_ENTRY(8533, 8533_E),
+	CPU_TYPE_ENTRY(8536, 8536),
+	CPU_TYPE_ENTRY(8536, 8536_E),
 	CPU_TYPE_ENTRY(8540, 8540),
 	CPU_TYPE_ENTRY(8541, 8541),
 	CPU_TYPE_ENTRY(8541, 8541_E),
@@ -89,6 +91,9 @@
 	svr = get_svr();
 	ver = SVR_SOC_VER(svr);
 	major = SVR_MAJ(svr);
+#ifdef CONFIG_MPC8536
+	major &= 0x7; /* the msb of this nibble is a mfg code */
+#endif
 	minor = SVR_MIN(svr);
 
 	puts("CPU:   ");
@@ -154,7 +159,8 @@
 #endif
 	clkdiv = lcrr & 0x0f;
 	if (clkdiv == 2 || clkdiv == 4 || clkdiv == 8) {
-#if defined(CONFIG_MPC8548) || defined(CONFIG_MPC8544) || defined(CONFIG_MPC8572)
+#if defined(CONFIG_MPC8548) || defined(CONFIG_MPC8544) || \
+    defined(CONFIG_MPC8572) || defined(CONFIG_MPC8536)
 		/*
 		 * Yes, the entire PQ38 family use the same
 		 * bit-representation for twice the clock divider values.
diff --git a/cpu/mpc85xx/cpu_init.c b/cpu/mpc85xx/cpu_init.c
index 4feb751..783c5ba 100644
--- a/cpu/mpc85xx/cpu_init.c
+++ b/cpu/mpc85xx/cpu_init.c
@@ -37,6 +37,10 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifdef CONFIG_MPC8536
+extern void fsl_serdes_init(void);
+#endif
+
 #ifdef CONFIG_QE
 extern qe_iop_conf_t qe_iop_conf_tab[];
 extern void qe_config_iopin(u8 port, u8 pin, int dir,
@@ -240,6 +244,9 @@
 	/* Config QE ioports */
 	config_qe_ioports();
 #endif
+#if defined(CONFIG_MPC8536)
+	fsl_serdes_init();
+#endif
 
 }
 
diff --git a/cpu/mpc85xx/mpc8536_serdes.c b/cpu/mpc85xx/mpc8536_serdes.c
new file mode 100644
index 0000000..ae091e6
--- /dev/null
+++ b/cpu/mpc85xx/mpc8536_serdes.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008 Freescale Semicondutor, Inc. All rights reserved.
+ *	Dave Liu <daveliu@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/immap_85xx.h>
+
+/* PORDEVSR register */
+#define GUTS_PORDEVSR_OFFS		0xc
+#define GUTS_PORDEVSR_SERDES2_IO_SEL	0x38000000
+#define GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT	27
+
+/* SerDes CR0 register */
+#define	FSL_SRDSCR0_OFFS	0x0
+#define FSL_SRDSCR0_TXEQA_MASK	0x00007000
+#define FSL_SRDSCR0_TXEQA_SGMII	0x00004000
+#define FSL_SRDSCR0_TXEQA_SATA	0x00001000
+#define FSL_SRDSCR0_TXEQE_MASK	0x00000700
+#define FSL_SRDSCR0_TXEQE_SGMII	0x00000400
+#define FSL_SRDSCR0_TXEQE_SATA	0x00000100
+
+/* SerDes CR1 register */
+#define FSL_SRDSCR1_OFFS	0x4
+#define FSL_SRDSCR1_LANEA_MASK	0x80200000
+#define FSL_SRDSCR1_LANEA_OFF	0x80200000
+#define FSL_SRDSCR1_LANEE_MASK	0x08020000
+#define FSL_SRDSCR1_LANEE_OFF	0x08020000
+
+/* SerDes CR2 register */
+#define FSL_SRDSCR2_OFFS	0x8
+#define FSL_SRDSCR2_EICA_MASK	0x00001f00
+#define FSL_SRDSCR2_EICA_SGMII	0x00000400
+#define FSL_SRDSCR2_EICA_SATA	0x00001400
+#define FSL_SRDSCR2_EICE_MASK	0x0000001f
+#define FSL_SRDSCR2_EICE_SGMII	0x00000004
+#define FSL_SRDSCR2_EICE_SATA	0x00000014
+
+/* SerDes CR3 register */
+#define FSL_SRDSCR3_OFFS	0xc
+#define FSL_SRDSCR3_LANEA_MASK	0x3f000700
+#define FSL_SRDSCR3_LANEA_SGMII	0x00000000
+#define FSL_SRDSCR3_LANEA_SATA	0x15000500
+#define FSL_SRDSCR3_LANEE_MASK	0x003f0007
+#define FSL_SRDSCR3_LANEE_SGMII	0x00000000
+#define FSL_SRDSCR3_LANEE_SATA	0x00150005
+
+void fsl_serdes_init(void)
+{
+	void *guts = (void *)(CFG_MPC85xx_GUTS_ADDR);
+	void *sd = (void *)CFG_MPC85xx_SERDES2_ADDR;
+	u32 pordevsr = in_be32(guts + GUTS_PORDEVSR_OFFS);
+	u32 srds2_io_sel;
+	u32 tmp;
+
+	/* parse the SRDS2_IO_SEL of PORDEVSR */
+	srds2_io_sel = (pordevsr & GUTS_PORDEVSR_SERDES2_IO_SEL)
+		       >> GUTS_PORDEVSR_SERDES2_IO_SEL_SHIFT;
+
+	switch (srds2_io_sel) {
+	case 1:	/* Lane A - SATA1, Lane E - SATA2 */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SATA;
+		tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
+		tmp |= FSL_SRDSCR0_TXEQE_SATA;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SATA;
+		tmp &= ~FSL_SRDSCR2_EICE_MASK;
+		tmp |= FSL_SRDSCR2_EICE_SATA;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SATA;
+		tmp &= ~FSL_SRDSCR3_LANEE_MASK;
+		tmp |= FSL_SRDSCR3_LANEE_SATA;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 3: /* Lane A - SATA1, Lane E - disabled */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SATA;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		tmp |= FSL_SRDSCR1_LANEE_OFF;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SATA;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SATA;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 4: /* Lane A - eTSEC1 SGMII, Lane E - eTSEC3 SGMII */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SGMII;
+		tmp &= ~FSL_SRDSCR0_TXEQE_MASK;
+		tmp |= FSL_SRDSCR0_TXEQE_SGMII;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SGMII;
+		tmp &= ~FSL_SRDSCR2_EICE_MASK;
+		tmp |= FSL_SRDSCR2_EICE_SGMII;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SGMII;
+		tmp &= ~FSL_SRDSCR3_LANEE_MASK;
+		tmp |= FSL_SRDSCR3_LANEE_SGMII;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 6: /* Lane A - eTSEC1 SGMII, Lane E - disabled */
+		/* CR 0 */
+		tmp = in_be32(sd + FSL_SRDSCR0_OFFS);
+		tmp &= ~FSL_SRDSCR0_TXEQA_MASK;
+		tmp |= FSL_SRDSCR0_TXEQA_SGMII;
+		out_be32(sd + FSL_SRDSCR0_OFFS, tmp);
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		tmp |= FSL_SRDSCR1_LANEE_OFF;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		/* CR 2 */
+		tmp = in_be32(sd + FSL_SRDSCR2_OFFS);
+		tmp &= ~FSL_SRDSCR2_EICA_MASK;
+		tmp |= FSL_SRDSCR2_EICA_SGMII;
+		out_be32(sd + FSL_SRDSCR2_OFFS, tmp);
+		/* CR 3 */
+		tmp = in_be32(sd + FSL_SRDSCR3_OFFS);
+		tmp &= ~FSL_SRDSCR3_LANEA_MASK;
+		tmp |= FSL_SRDSCR3_LANEA_SGMII;
+		out_be32(sd + FSL_SRDSCR3_OFFS, tmp);
+		break;
+	case 7: /* Lane A - disabled, Lane E - disabled */
+		/* CR 1 */
+		tmp = in_be32(sd + FSL_SRDSCR1_OFFS);
+		tmp &= ~FSL_SRDSCR1_LANEA_MASK;
+		tmp |= FSL_SRDSCR1_LANEA_OFF;
+		tmp &= ~FSL_SRDSCR1_LANEE_MASK;
+		tmp |= FSL_SRDSCR1_LANEE_OFF;
+		out_be32(sd + FSL_SRDSCR1_OFFS, tmp);
+		break;
+	default:
+		break;
+	}
+}
diff --git a/cpu/mpc85xx/speed.c b/cpu/mpc85xx/speed.c
index 699441b4..1cda1e3 100644
--- a/cpu/mpc85xx/speed.c
+++ b/cpu/mpc85xx/speed.c
@@ -110,6 +110,10 @@
 #endif
 	gd->i2c2_clk = gd->i2c1_clk;
 
+#if defined(CONFIG_MPC8536)
+	gd->sdhc_clk = gd->bus_clk / 2;
+#endif
+
 #if defined(CONFIG_CPM2)
 	gd->vco_out = 2*sys_info.freqSystemBus;
 	gd->cpm_clk = gd->vco_out / 2;