MIPS: BCM63XX: Add support for bcm6368 CPU.

Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2892/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig
index fb177d6..6b1b9ad 100644
--- a/arch/mips/bcm63xx/Kconfig
+++ b/arch/mips/bcm63xx/Kconfig
@@ -20,6 +20,10 @@
 config BCM63XX_CPU_6358
 	bool "support 6358 CPU"
 	select HW_HAS_PCI
+
+config BCM63XX_CPU_6368
+	bool "support 6368 CPU"
+	select HW_HAS_PCI
 endmenu
 
 source "arch/mips/bcm63xx/boards/Kconfig"
diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c
index 2c68ee9..9d57c71 100644
--- a/arch/mips/bcm63xx/clk.c
+++ b/arch/mips/bcm63xx/clk.c
@@ -10,6 +10,7 @@
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <bcm63xx_cpu.h>
 #include <bcm63xx_io.h>
 #include <bcm63xx_regs.h>
@@ -113,6 +114,34 @@
 };
 
 /*
+ * Ethernet switch clock
+ */
+static void enetsw_set(struct clk *clk, int enable)
+{
+	if (!BCMCPU_IS_6368())
+		return;
+	bcm_hwclock_set(CKCTL_6368_ROBOSW_CLK_EN |
+			CKCTL_6368_SWPKT_USB_EN |
+			CKCTL_6368_SWPKT_SAR_EN, enable);
+	if (enable) {
+		u32 val;
+
+		/* reset switch core afer clock change */
+		val = bcm_perf_readl(PERF_SOFTRESET_6368_REG);
+		val &= ~SOFTRESET_6368_ENETSW_MASK;
+		bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+		msleep(10);
+		val |= SOFTRESET_6368_ENETSW_MASK;
+		bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+		msleep(10);
+	}
+}
+
+static struct clk clk_enetsw = {
+	.set	= enetsw_set,
+};
+
+/*
  * PCM clock
  */
 static void pcm_set(struct clk *clk, int enable)
@@ -131,9 +160,10 @@
  */
 static void usbh_set(struct clk *clk, int enable)
 {
-	if (!BCMCPU_IS_6348())
-		return;
-	bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
+	if (BCMCPU_IS_6348())
+		bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
+	else if (BCMCPU_IS_6368())
+		bcm_hwclock_set(CKCTL_6368_USBH_CLK_EN, enable);
 }
 
 static struct clk clk_usbh = {
@@ -162,6 +192,36 @@
 };
 
 /*
+ * XTM clock
+ */
+static void xtm_set(struct clk *clk, int enable)
+{
+	if (!BCMCPU_IS_6368())
+		return;
+
+	bcm_hwclock_set(CKCTL_6368_SAR_CLK_EN |
+			CKCTL_6368_SWPKT_SAR_EN, enable);
+
+	if (enable) {
+		u32 val;
+
+		/* reset sar core afer clock change */
+		val = bcm_perf_readl(PERF_SOFTRESET_6368_REG);
+		val &= ~SOFTRESET_6368_SAR_MASK;
+		bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+		mdelay(1);
+		val |= SOFTRESET_6368_SAR_MASK;
+		bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
+		mdelay(1);
+	}
+}
+
+
+static struct clk clk_xtm = {
+	.set	= xtm_set,
+};
+
+/*
  * Internal peripheral clock
  */
 static struct clk clk_periph = {
@@ -204,12 +264,16 @@
 		return &clk_enet0;
 	if (!strcmp(id, "enet1"))
 		return &clk_enet1;
+	if (!strcmp(id, "enetsw"))
+		return &clk_enetsw;
 	if (!strcmp(id, "ephy"))
 		return &clk_ephy;
 	if (!strcmp(id, "usbh"))
 		return &clk_usbh;
 	if (!strcmp(id, "spi"))
 		return &clk_spi;
+	if (!strcmp(id, "xtm"))
+		return &clk_xtm;
 	if (!strcmp(id, "periph"))
 		return &clk_periph;
 	if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
index 8bd5133..8094168 100644
--- a/arch/mips/bcm63xx/cpu.c
+++ b/arch/mips/bcm63xx/cpu.c
@@ -63,6 +63,15 @@
 
 };
 
+static const unsigned long bcm6368_regs_base[] = {
+	__GEN_CPU_REGS_TABLE(6368)
+};
+
+static const int bcm6368_irqs[] = {
+	__GEN_CPU_IRQ_TABLE(6368)
+
+};
+
 u16 __bcm63xx_get_cpu_id(void)
 {
 	return bcm63xx_cpu_id;
@@ -89,20 +98,19 @@
 
 static unsigned int detect_cpu_clock(void)
 {
-	unsigned int tmp, n1 = 0, n2 = 0, m1 = 0;
-
-	/* BCM6338 has a fixed 240 Mhz frequency */
-	if (BCMCPU_IS_6338())
+	switch (bcm63xx_get_cpu_id()) {
+	case BCM6338_CPU_ID:
+		/* BCM6338 has a fixed 240 Mhz frequency */
 		return 240000000;
 
-	/* BCM6345 has a fixed 140Mhz frequency */
-	if (BCMCPU_IS_6345())
+	case BCM6345_CPU_ID:
+		/* BCM6345 has a fixed 140Mhz frequency */
 		return 140000000;
 
-	/*
-	 * frequency depends on PLL configuration:
-	 */
-	if (BCMCPU_IS_6348()) {
+	case BCM6348_CPU_ID:
+	{
+		unsigned int tmp, n1, n2, m1;
+
 		/* 16MHz * (N1 + 1) * (N2 + 2) / (M1_CPU + 1) */
 		tmp = bcm_perf_readl(PERF_MIPSPLLCTL_REG);
 		n1 = (tmp & MIPSPLLCTL_N1_MASK) >> MIPSPLLCTL_N1_SHIFT;
@@ -111,17 +119,47 @@
 		n1 += 1;
 		n2 += 2;
 		m1 += 1;
+		return (16 * 1000000 * n1 * n2) / m1;
 	}
 
-	if (BCMCPU_IS_6358()) {
+	case BCM6358_CPU_ID:
+	{
+		unsigned int tmp, n1, n2, m1;
+
 		/* 16MHz * N1 * N2 / M1_CPU */
 		tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_REG);
 		n1 = (tmp & DMIPSPLLCFG_N1_MASK) >> DMIPSPLLCFG_N1_SHIFT;
 		n2 = (tmp & DMIPSPLLCFG_N2_MASK) >> DMIPSPLLCFG_N2_SHIFT;
 		m1 = (tmp & DMIPSPLLCFG_M1_MASK) >> DMIPSPLLCFG_M1_SHIFT;
+		return (16 * 1000000 * n1 * n2) / m1;
 	}
 
-	return (16 * 1000000 * n1 * n2) / m1;
+	case BCM6368_CPU_ID:
+	{
+		unsigned int tmp, p1, p2, ndiv, m1;
+
+		/* (64MHz / P1) * P2 * NDIV / M1_CPU */
+		tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_6368_REG);
+
+		p1 = (tmp & DMIPSPLLCFG_6368_P1_MASK) >>
+			DMIPSPLLCFG_6368_P1_SHIFT;
+
+		p2 = (tmp & DMIPSPLLCFG_6368_P2_MASK) >>
+			DMIPSPLLCFG_6368_P2_SHIFT;
+
+		ndiv = (tmp & DMIPSPLLCFG_6368_NDIV_MASK) >>
+			DMIPSPLLCFG_6368_NDIV_SHIFT;
+
+		tmp = bcm_ddr_readl(DDR_DMIPSPLLDIV_6368_REG);
+		m1 = (tmp & DMIPSPLLDIV_6368_MDIV_MASK) >>
+			DMIPSPLLDIV_6368_MDIV_SHIFT;
+
+		return (((64 * 1000000) / p1) * p2 * ndiv) / m1;
+	}
+
+	default:
+		BUG();
+	}
 }
 
 /*
@@ -143,7 +181,7 @@
 		banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1;
 	}
 
-	if (BCMCPU_IS_6358()) {
+	if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
 		val = bcm_memc_readl(MEMC_CFG_REG);
 		rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
 		cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
@@ -188,9 +226,18 @@
 		bcm63xx_irqs = bcm6345_irqs;
 		break;
 	case CPU_BMIPS4350:
-		expected_cpu_id = BCM6358_CPU_ID;
-		bcm63xx_regs_base = bcm6358_regs_base;
-		bcm63xx_irqs = bcm6358_irqs;
+		switch (read_c0_prid() & 0xf0) {
+		case 0x10:
+			expected_cpu_id = BCM6358_CPU_ID;
+			bcm63xx_regs_base = bcm6358_regs_base;
+			bcm63xx_irqs = bcm6358_irqs;
+			break;
+		case 0x30:
+			expected_cpu_id = BCM6368_CPU_ID;
+			bcm63xx_regs_base = bcm6368_regs_base;
+			bcm63xx_irqs = bcm6368_irqs;
+			break;
+		}
 		break;
 	}
 
diff --git a/arch/mips/bcm63xx/dev-uart.c b/arch/mips/bcm63xx/dev-uart.c
index c2963da..d6e42c6 100644
--- a/arch/mips/bcm63xx/dev-uart.c
+++ b/arch/mips/bcm63xx/dev-uart.c
@@ -54,7 +54,7 @@
 	if (id >= ARRAY_SIZE(bcm63xx_uart_devices))
 		return -ENODEV;
 
-	if (id == 1 && !BCMCPU_IS_6358())
+	if (id == 1 && (!BCMCPU_IS_6358() && !BCMCPU_IS_6368()))
 		return -ENODEV;
 
 	if (id == 0) {
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
index 9f53884..9a216a4 100644
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -71,6 +71,17 @@
 #define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6358
 #define ext_irq_cfg_reg2	0
 #endif
+#ifdef CONFIG_BCM63XX_CPU_6368
+#define irq_stat_reg		PERF_IRQSTAT_6368_REG
+#define irq_mask_reg		PERF_IRQMASK_6368_REG
+#define irq_bits		64
+#define is_ext_irq_cascaded	1
+#define ext_irq_start		(BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE)
+#define ext_irq_end		(BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE)
+#define ext_irq_count		6
+#define ext_irq_cfg_reg1	PERF_EXTIRQ_CFG_REG_6368
+#define ext_irq_cfg_reg2	PERF_EXTIRQ_CFG_REG2_6368
+#endif
 
 #if irq_bits == 32
 #define dispatch_internal			__dispatch_internal
@@ -134,6 +145,17 @@
 		ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE;
 		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358;
 		break;
+	case BCM6368_CPU_ID:
+		irq_stat_addr += PERF_IRQSTAT_6368_REG;
+		irq_mask_addr += PERF_IRQMASK_6368_REG;
+		irq_bits = 64;
+		ext_irq_count = 6;
+		is_ext_irq_cascaded = 1;
+		ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE;
+		ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE;
+		ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368;
+		ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368;
+		break;
 	default:
 		BUG();
 	}
@@ -406,7 +428,7 @@
 			reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq);
 	}
 
-	if (BCMCPU_IS_6338() || BCMCPU_IS_6358()) {
+	if (BCMCPU_IS_6338() || BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
 		if (levelsense)
 			reg |= EXTIRQ_CFG_LEVELSENSE(irq);
 		else
diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c
index be252ef..99d7f40 100644
--- a/arch/mips/bcm63xx/prom.c
+++ b/arch/mips/bcm63xx/prom.c
@@ -32,9 +32,12 @@
 		mask = CKCTL_6345_ALL_SAFE_EN;
 	else if (BCMCPU_IS_6348())
 		mask = CKCTL_6348_ALL_SAFE_EN;
-	else
-		/* BCMCPU_IS_6358() */
+	else if (BCMCPU_IS_6358())
 		mask = CKCTL_6358_ALL_SAFE_EN;
+	else if (BCMCPU_IS_6368())
+		mask = CKCTL_6368_ALL_SAFE_EN;
+	else
+		mask = 0;
 
 	reg = bcm_perf_readl(PERF_CKCTL_REG);
 	reg &= ~mask;