[PATCH 1/2] ARM: imx: enable smp for i.MX7D
Frank.Li at freescale.com
Frank.Li at freescale.com
Mon May 11 14:15:54 PDT 2015
From: Frank Li <Frank.Li at freescale.com>
i.MX7D have two cores.
enable multicore support.
enable cpu hotplug support.
Signed-off-by: Frank Li <Frank.Li at freescale.com>
Signed-off-by: Anson Huang <b20788 at freescale.com>
---
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/Makefile | 2 +-
arch/arm/mach-imx/common.h | 6 ++
arch/arm/mach-imx/gpcv2.c | 137 +++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-imx/headsmp.S | 5 ++
arch/arm/mach-imx/hotplug.c | 7 +++
arch/arm/mach-imx/mach-imx7d.c | 2 +
arch/arm/mach-imx/platsmp.c | 14 +++++
arch/arm/mach-imx/src.c | 38 +++++++++++-
9 files changed, 208 insertions(+), 4 deletions(-)
create mode 100644 arch/arm/mach-imx/gpcv2.c
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 1d87078..0e50ce7 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -586,6 +586,7 @@ config SOC_IMX7D
bool "i.MX7 Dual support"
select PINCTRL_IMX7D
select ARM_GIC
+ select ARM_ARCH_TIMER
help
This enables support for Freescale i.MX7 Dual processor.
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 40df12a..8a83366 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -74,7 +74,7 @@ obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
obj-$(CONFIG_MACH_IMX35_DT) += imx35-dt.o
obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
-obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
+obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o gpcv2.o
obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
obj-$(CONFIG_HAVE_IMX_SRC) += src.o
ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index d1e2873..216031b 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -67,6 +67,7 @@ void imx_gpc_check_dt(void);
void imx_gpc_set_arm_power_in_lpm(bool power_off);
void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw);
void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw);
+void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn);
enum mxc_cpu_pwr_mode {
WAIT_CLOCKED, /* wfi only */
@@ -86,11 +87,13 @@ enum mx3_cpu_pwr_mode {
void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
void imx_enable_cpu(int cpu, bool enable);
+void imx_enable_cpu_ca7(int cpu, bool enable);
void imx_set_cpu_jump(int cpu, void *jump_addr);
u32 imx_get_cpu_arg(int cpu);
void imx_set_cpu_arg(int cpu, u32 arg);
#ifdef CONFIG_SMP
void v7_secondary_startup(void);
+void ca7_secondary_startup(void);
void imx_scu_map_io(void);
void imx_smp_prepare(void);
#else
@@ -111,9 +114,11 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode);
void imx6q_set_int_mem_clk_lpm(bool enable);
void imx6sl_set_wait_clk(bool enter);
int imx_mmdc_get_ddr_type(void);
+int imx_gpcv2_init(const char *gpc_compat);
void imx_cpu_die(unsigned int cpu);
int imx_cpu_kill(unsigned int cpu);
+int imx_cpu_ca7_kill(unsigned int cpu);
#ifdef CONFIG_SUSPEND
void v7_cpu_resume(void);
@@ -149,6 +154,7 @@ static inline void imx_init_l2cache(void) {}
#endif
extern struct smp_operations imx_smp_ops;
+extern struct smp_operations imx_smp_ca7_ops;
extern struct smp_operations ls1021a_smp_ops;
#endif
diff --git a/arch/arm/mach-imx/gpcv2.c b/arch/arm/mach-imx/gpcv2.c
new file mode 100644
index 0000000..554dd5e
--- /dev/null
+++ b/arch/arm/mach-imx/gpcv2.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regulator/consumer.h>
+#include <linux/irqchip/arm-gic.h>
+#include "common.h"
+#include "hardware.h"
+
+#define IMR_NUM 4
+#define GPC_LPCR_A7_BSC 0x0
+#define GPC_LPCR_A7_AD 0x4
+#define GPC_LPCR_M4 0x8
+#define GPC_SLPCR 0x14
+#define GPC_PGC_ACK_SEL_A7 0x24
+#define GPC_MISC 0x2c
+#define GPC_IMR1_CORE0 0x30
+#define GPC_IMR1_CORE1 0x40
+#define GPC_SLOT0_CFG 0xb0
+#define GPC_PGC_CPU_MAPPING 0xec
+#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
+#define GPC_PU_PGC_SW_PUP_REQ 0xf8
+#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
+#define GPC_PU_PGC_SW_PDN_REQ 0x104
+#define GPC_GTOR 0x124
+#define GPC_PGC_C0 0x800
+#define GPC_PGC_C1 0x840
+#define GPC_PGC_SCU 0x880
+#define GPC_PGC_FM 0xa00
+#define GPC_PGC_MIPI_PHY 0xc00
+#define GPC_PGC_PCIE_PHY 0xc40
+#define GPC_PGC_USB_OTG1_PHY 0xc80
+#define GPC_PGC_USB_OTG2_PHY 0xcc0
+#define GPC_PGC_USB_HSIC_PHY 0xd00
+
+#define BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP 0x70000000
+#define BM_LPCR_A7_BSC_CPU_CLK_ON_LPM 0x4000
+#define BM_LPCR_A7_BSC_LPM1 0xc
+#define BM_LPCR_A7_BSC_LPM0 0x3
+#define BP_LPCR_A7_BSC_LPM1 2
+#define BP_LPCR_A7_BSC_LPM0 0
+#define BM_LPCR_M4_MASK_DSM_TRIGGER 0x80000000
+#define BM_SLPCR_EN_DSM 0x80000000
+#define BM_SLPCR_RBC_EN 0x40000000
+#define BM_SLPCR_VSTBY 0x4
+#define BM_SLPCR_SBYOS 0x2
+#define BM_SLPCR_BYPASS_PMIC_READY 0x1
+
+#define BM_LPCR_A7_AD_EN_C1_PUP 0x800
+#define BM_LPCR_A7_AD_EN_C1_IRQ_PUP 0x400
+#define BM_LPCR_A7_AD_EN_C0_PUP 0x200
+#define BM_LPCR_A7_AD_EN_C0_IRQ_PUP 0x100
+#define BM_LPCR_A7_AD_EN_PLAT_PDN 0x10
+#define BM_LPCR_A7_AD_EN_C1_PDN 0x8
+#define BM_LPCR_A7_AD_EN_C1_WFI_PDN 0x4
+#define BM_LPCR_A7_AD_EN_C0_PDN 0x2
+#define BM_LPCR_A7_AD_EN_C0_WFI_PDN 0x1
+
+#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2
+
+#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK 0x80000000
+#define BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK 0x8000
+
+#define BP_LPCR_A7_BSC_IRQ_SRC 28
+
+#define MAX_SLOT_NUMBER 10
+#define A7_LPM_WAIT 0x5
+#define A7_LPM_STOP 0xa
+
+#define GPC_MAX_IRQS (IMR_NUM * 32)
+
+enum imx_gpc_slot {
+ CORE0_A7,
+ CORE1_A7,
+ SCU_A7,
+ FAST_MEGA_MIX,
+ MIPI_PHY,
+ PCIE_PHY,
+ USB_OTG1_PHY,
+ USB_OTG2_PHY,
+ USB_HSIC_PHY,
+ CORE0_M4,
+};
+
+static void __iomem *gpc_base;
+
+
+void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset)
+{
+ writel_relaxed(enable, gpc_base + offset);
+}
+
+void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn)
+{
+
+ u32 val = readl_relaxed(gpc_base + (pdn ?
+ GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ));
+
+ imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1);
+ val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
+ writel_relaxed(val, gpc_base + (pdn ?
+ GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ));
+
+ while ((readl_relaxed(gpc_base + (pdn ?
+ GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)) &
+ BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0)
+ ;
+ imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1);
+}
+
+int __init imx_gpcv2_init(const char *gpc_compat)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, gpc_compat);
+ gpc_base = of_iomap(np, 0);
+ if (WARN_ON(!gpc_base))
+ return -ENOMEM;
+
+ return 0;
+}
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index de5047c..95467c7 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -29,3 +29,8 @@ ENTRY(v7_secondary_startup)
set_diag_reg
b secondary_startup
ENDPROC(v7_secondary_startup)
+
+ENTRY(ca7_secondary_startup)
+ bl v7_invalidate_l1
+ b secondary_startup
+ENDPROC(ca7_secondary_startup)
diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c
index b35e99c..9a7a00f 100644
--- a/arch/arm/mach-imx/hotplug.c
+++ b/arch/arm/mach-imx/hotplug.c
@@ -68,3 +68,10 @@ int imx_cpu_kill(unsigned int cpu)
imx_set_cpu_arg(cpu, 0);
return 1;
}
+
+int imx_cpu_ca7_kill(unsigned int cpu)
+{
+ if (imx_cpu_kill(cpu))
+ imx_gpcv2_set_core1_pdn_pup_by_software(true);
+ return 1;
+}
diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c
index 4d4a190..6657645 100644
--- a/arch/arm/mach-imx/mach-imx7d.c
+++ b/arch/arm/mach-imx/mach-imx7d.c
@@ -27,6 +27,7 @@ static void __init imx7d_init_machine(void)
static void __init imx7d_init_irq(void)
{
imx_init_revision_from_anatop();
+ imx_gpcv2_init("fsl,imx7d-gpc");
imx_src_init();
irqchip_init();
}
@@ -37,6 +38,7 @@ static const char *imx7d_dt_compat[] __initconst = {
};
DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
+ .smp = smp_ops(imx_smp_ca7_ops),
.init_irq = imx7d_init_irq,
.init_machine = imx7d_init_machine,
.dt_compat = imx7d_dt_compat,
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index 7f27001..119f96a 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -98,6 +98,20 @@ struct smp_operations imx_smp_ops __initdata = {
#endif
};
+static int imx_ca7_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ imx_set_cpu_jump(cpu, ca7_secondary_startup);
+ imx_enable_cpu_ca7(cpu, true);
+ return 0;
+}
+
+struct smp_operations imx_smp_ca7_ops __initdata = {
+ .smp_boot_secondary = imx_ca7_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = imx_cpu_die,
+ .cpu_kill = imx_cpu_ca7_kill,
+#endif
+};
#define DCFG_CCSR_SCRATCHRW1 0x200
static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index 45f7f4e..f4ea055 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -30,8 +30,17 @@
#define BP_SRC_SCR_CORE1_RST 14
#define BP_SRC_SCR_CORE1_ENABLE 22
+/* below is for i.MX7D */
+#define SRC_GPR1_V2 0x074
+#define SRC_A7RCR0 0x004
+#define SRC_A7RCR1 0x008
+
+#define BP_SRC_A7RCR0_A7_CORE_RESET0 0
+#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1
+
static void __iomem *src_base;
static DEFINE_SPINLOCK(scr_lock);
+static int src_gpr_offset;
static const int sw_reset_bits[5] = {
BP_SRC_SCR_SW_GPU_RST,
@@ -96,23 +105,39 @@ void imx_enable_cpu(int cpu, bool enable)
spin_unlock(&scr_lock);
}
+void imx_enable_cpu_ca7(int cpu, bool enable)
+{
+ u32 mask, val;
+
+ cpu = cpu_logical_map(cpu);
+ spin_lock(&scr_lock);
+ if (enable)
+ imx_gpcv2_set_core1_pdn_pup_by_software(false);
+ mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1);
+ val = readl_relaxed(src_base + SRC_A7RCR1);
+ val = enable ? val | mask : val & ~mask;
+ writel_relaxed(val, src_base + SRC_A7RCR1);
+ spin_unlock(&scr_lock);
+
+}
+
void imx_set_cpu_jump(int cpu, void *jump_addr)
{
cpu = cpu_logical_map(cpu);
writel_relaxed(virt_to_phys(jump_addr),
- src_base + SRC_GPR1 + cpu * 8);
+ src_base + src_gpr_offset + cpu * 8);
}
u32 imx_get_cpu_arg(int cpu)
{
cpu = cpu_logical_map(cpu);
- return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4);
+ return readl_relaxed(src_base + src_gpr_offset + cpu * 8 + 4);
}
void imx_set_cpu_arg(int cpu, u32 arg)
{
cpu = cpu_logical_map(cpu);
- writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4);
+ writel_relaxed(arg, src_base + src_gpr_offset + cpu * 8 + 4);
}
void __init imx_src_init(void)
@@ -120,6 +145,8 @@ void __init imx_src_init(void)
struct device_node *np;
u32 val;
+ src_gpr_offset = SRC_GPR1;
+
np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src");
if (!np)
return;
@@ -127,6 +154,11 @@ void __init imx_src_init(void)
WARN_ON(!src_base);
imx_reset_controller.of_node = np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-src");
+ if (np)
+ src_gpr_offset = SRC_GPR1_V2;
+
if (IS_ENABLED(CONFIG_RESET_CONTROLLER))
reset_controller_register(&imx_reset_controller);
--
1.9.1
More information about the linux-arm-kernel
mailing list