summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnson Huang <Anson.Huang@nxp.com>2016-11-08 00:06:50 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:25:13 +0800
commit209f156a568f33ea84664b5d051405ffe909db51 (patch)
tree1986cdccce9b789788c408fb55308c7f45343511
parent37e61480a1efa88fb7c5e3387dcad35b250e4008 (diff)
MLK-13441-7 ARM: imx: add i.mx7ulp MSL support
Add i.MX7ULP MSL support. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
-rw-r--r--arch/arm/mach-imx/Kconfig13
-rw-r--r--arch/arm/mach-imx/Makefile1
-rw-r--r--arch/arm/mach-imx/common.h14
-rw-r--r--arch/arm/mach-imx/cpu.c3
-rw-r--r--arch/arm/mach-imx/hardware.h1
-rw-r--r--arch/arm/mach-imx/mach-imx7ulp.c58
-rw-r--r--arch/arm/mach-imx/mx7ulp.h36
-rw-r--r--arch/arm/mach-imx/mxc.h6
-rw-r--r--arch/arm/mach-imx/pm-imx7ulp.c232
9 files changed, 364 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index d6959fc477a4..2174826338f3 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -614,6 +614,19 @@ config SOC_IMX6SLL
help
This enables support for Freescale i.MX6 SLL processor.
+config SOC_IMX7ULP
+ bool "i.MX7ULP support"
+ select CPU_V7
+ select ARM_GIC
+ select CLKSRC_IMX_TPM
+ select HAVE_IMX_MU
+ select PINCTRL_IMX7ULP
+ select HAVE_IMX_RPMSG
+ select RPMSG
+
+ help
+ This enables support for Freescale i.MX7 Ultra Low Power processor.
+
config SOC_VF610
bool "Vybrid Family VF610 support"
select ARM_GIC if ARCH_MULTI_V7
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index b19fbeff19c0..37886485fcb0 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o ddr3_freq_imx6sx.o \
obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o ddr3_freq_imx6sx.o \
lpddr2_freq_imx6sx.o
obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o
+obj-$(CONFIG_SOC_IMX7ULP) += mach-imx7ulp.o pm-imx7ulp.o
ifeq ($(CONFIG_SUSPEND),y)
AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index f4059adf8163..325816d7de3e 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -102,6 +102,17 @@ enum mx3_cpu_pwr_mode {
MX3_SLEEP,
};
+enum imx7ulp_cpu_pwr_mode {
+ HSRUN,
+ RUN,
+ VLPR,
+ WAIT,
+ VLPW,
+ STOP,
+ VLPS,
+ VLLS,
+};
+
void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
void imx_enable_cpu(int cpu, bool enable);
@@ -118,6 +129,7 @@ static inline void imx_smp_prepare(void) {}
#endif
void imx6_pm_map_io(void);
void imx7_pm_map_io(void);
+void imx7ulp_pm_map_io(void);
void imx_src_init(void);
void imx_gpc_pre_suspend(bool arm_power_off);
void imx_gpc_post_resume(void);
@@ -154,6 +166,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode);
void imx6_set_int_mem_clk_lpm(bool enable);
void imx6sl_set_wait_clk(bool enter);
void imx6_enet_mac_init(const char *enet_compat, const char *ocotp_compat);
+int imx7ulp_set_lpm(enum imx7ulp_cpu_pwr_mode mode);
#ifdef CONFIG_HAVE_IMX_MMDC
int imx_mmdc_get_ddr_type(void);
#else
@@ -198,6 +211,7 @@ void imx6sl_pm_init(void);
void imx6sx_pm_init(void);
void imx6ul_pm_init(void);
void imx6ull_pm_init(void);
+void imx7ulp_pm_init(void);
void imx6q_pm_set_ccm_base(void __iomem *base);
#ifdef CONFIG_PM
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index 9391cd1bad9c..e345eb60827e 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -144,6 +144,9 @@ struct device * __init imx_soc_device_init(void)
case MXC_CPU_IMX6SLL:
soc_id = "i.MX6SLL";
break;
+ case MXC_CPU_IMX7ULP:
+ soc_id = "i.MX7ULP";
+ break;
default:
soc_id = "Unknown";
}
diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h
index fe681cc89c93..665c596a0b76 100644
--- a/arch/arm/mach-imx/hardware.h
+++ b/arch/arm/mach-imx/hardware.h
@@ -117,6 +117,7 @@
#include "mx27.h"
#include "mx6.h"
#include "mx7.h"
+#include "mx7ulp.h"
#define imx_map_entry(soc, name, _type) { \
.virtual = soc ## _IO_P2V(soc ## _ ## name ## _BASE_ADDR), \
diff --git a/arch/arm/mach-imx/mach-imx7ulp.c b/arch/arm/mach-imx/mach-imx7ulp.c
new file mode 100644
index 000000000000..f54e9a824e17
--- /dev/null
+++ b/arch/arm/mach-imx/mach-imx7ulp.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/irqchip.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "common.h"
+#include "cpuidle.h"
+#include "hardware.h"
+
+static void __init imx7ulp_init_machine(void)
+{
+ struct device *parent;
+
+ parent = imx_soc_device_init();
+ if (parent == NULL)
+ pr_warn("failed to initialize soc device\n");
+
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static void __init imx7ulp_init_irq(void)
+{
+ mxc_set_cpu_type(MXC_CPU_IMX7ULP);
+
+ irqchip_init();
+ imx7ulp_pm_init();
+}
+
+static void __init imx7ulp_map_io(void)
+{
+ imx7ulp_pm_map_io();
+}
+
+static void __init imx7ulp_init_late(void)
+{
+
+}
+
+static const char *const imx7ulp_dt_compat[] __initconst = {
+ "fsl,imx7ulp",
+ NULL,
+};
+
+DT_MACHINE_START(IMX7ulp, "Freescale i.MX7ULP (Device Tree)")
+ .map_io = imx7ulp_map_io,
+ .init_irq = imx7ulp_init_irq,
+ .init_machine = imx7ulp_init_machine,
+ .init_late = imx7ulp_init_late,
+ .dt_compat = imx7ulp_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-imx/mx7ulp.h b/arch/arm/mach-imx/mx7ulp.h
new file mode 100644
index 000000000000..5b912531d799
--- /dev/null
+++ b/arch/arm/mach-imx/mx7ulp.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * * This program is free software; you can redistribute it and/or modify
+ * * it under the terms of the GNU General Public License version 2 as
+ * * published by the Free Software Foundation.
+ * */
+
+#ifndef __ASM_ARCH_MX7ULP_IOMAP_H__
+#define __ASM_ARCH_MX7ULP_IOMAP_H__
+
+#define MX7ULP_IO_P2V(x) IMX_IO_P2V(x)
+#define MX7ULP_IO_ADDRESS(x) IOMEM(MX7ULP_IO_P2V(x))
+
+#define MX7ULP_AIPS1_BASE_ADDR 0x40a00000
+#define MX7ULP_AIPS1_SIZE 0x400000
+#define MX7ULP_AIPS2_BASE_ADDR 0x41000000
+#define MX7ULP_AIPS2_SIZE 0x400000
+#define MX7ULP_PCC3_BASE_ADDR 0x40b30000
+#define MX7ULP_PCC3_SIZE 0x1000
+#define MX7ULP_SCG1_BASE_ADDR 0x403e0000
+#define MX7ULP_SCG1_SIZE 0x1000
+#define MX7ULP_SIM_BASE_ADDR 0x410a3000
+#define MX7ULP_SIM_SIZE 0x1000
+#define MX7ULP_MMDC_BASE_ADDR 0x40ab0000
+#define MX7ULP_MMDC_SIZE 0x1000
+#define MX7ULP_MMDC_IO_BASE_ADDR 0x40ad0000
+#define MX7ULP_MMDC_IO_SIZE 0x1000
+
+#define TT_ATTRIB_NON_CACHEABLE_1M 0x802
+#define MX7ULP_IRAM_TLB_SIZE 0x4000
+#define MX7ULP_SUSPEND_OCRAM_SIZE 0x1000
+
+#endif
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index 60aaec2a4b97..5dcda87d9308 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -42,6 +42,7 @@
#define MXC_CPU_IMX6ULL 0x65
#define MXC_CPU_IMX6SLL 0x67
#define MXC_CPU_IMX7D 0x72
+#define MXC_CPU_IMX7ULP 0xff /* TBD */
#define IMX_DDR_TYPE_DDR3 0
#define IMX_DDR_TYPE_LPDDR2 1
@@ -109,6 +110,11 @@ static inline bool cpu_is_imx7d(void)
return __mxc_cpu_type == MXC_CPU_IMX7D;
}
+static inline bool cpu_is_imx7ulp(void)
+{
+ return __mxc_cpu_type == MXC_CPU_IMX7ULP;
+}
+
struct cpu_op {
u32 cpu_rate;
};
diff --git a/arch/arm/mach-imx/pm-imx7ulp.c b/arch/arm/mach-imx/pm-imx7ulp.c
new file mode 100644
index 000000000000..d3a0b6748191
--- /dev/null
+++ b/arch/arm/mach-imx/pm-imx7ulp.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2016 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/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/genalloc.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
+#include <asm/mach/map.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include <asm/tlb.h>
+
+#include "common.h"
+#include "hardware.h"
+
+#define PMPROT 0x8
+#define PMCTRL 0x10
+#define PMSTAT 0x18
+#define SRS 0x20
+#define RPC 0x24
+#define SSRS 0x28
+#define SRIE 0x2c
+#define SRIF 0x30
+#define CSRE 0x34
+#define MR 0x40
+
+#define PMC_HSRUN 0x4
+#define PMC_RUN 0x8
+#define PMC_VLPR 0xc
+#define PMC_STOP 0x10
+#define PMC_VLPS 0x14
+#define PMC_LLS 0x18
+#define PMC_VLLS 0x1c
+#define PMC_STATUS 0x20
+#define PMC_CTRL 0x24
+#define PMC_SRAMCTRL_0 0x28
+#define PMC_SRAMCTRL_1 0x2c
+#define PMC_SRAMCTRL_2 0x30
+
+#define BM_PMPROT_AHSRUN (1 << 7)
+#define BM_PMPROT_AVLP (1 << 5)
+#define BM_PMPROT_ALLS (1 << 3)
+#define BM_PMPROT_AVLLS (1 << 1)
+
+#define BM_PMCTRL_STOPA (1 << 24)
+#define BM_PMCTRL_PSTOPO (3 << 16)
+#define BM_PMCTRL_RUNM (3 << 8)
+#define BM_PMCTRL_STOPM (7 << 0)
+
+#define BM_CTRL_LDOEN (1 << 31)
+#define BM_CTRL_LDOOKDIS (1 << 30)
+
+#define BM_VLLS_MON1P2HVDHP (1 << 5)
+#define BM_VLLS_MON1P2LVDHP (1 << 4)
+
+#define BP_PMCTRL_STOPM 0
+#define BP_PMCTRL_PSTOPO 16
+
+static void __iomem *smc1_base;
+static void __iomem *pmc0_base;
+
+extern unsigned long iram_tlb_base_addr;
+extern unsigned long iram_tlb_phys_addr;
+
+int imx7ulp_set_lpm(enum imx7ulp_cpu_pwr_mode mode)
+{
+ u32 val1 = BM_PMPROT_AVLP | BM_PMPROT_AVLLS;
+ u32 val2 = readl_relaxed(smc1_base + PMCTRL);
+ u32 val3 = readl_relaxed(pmc0_base + PMC_CTRL);
+
+ val2 &= ~(BM_PMCTRL_RUNM |
+ BM_PMCTRL_STOPM | BM_PMCTRL_PSTOPO);
+ val3 |= BM_CTRL_LDOOKDIS;
+
+ switch (mode) {
+ case RUN:
+ /* system/bus clock enabled */
+ val2 |= 0x3 << BP_PMCTRL_PSTOPO;
+ break;
+ case WAIT:
+ /* system clock disabled, bus clock enabled */
+ val2 |= 0x2 << BP_PMCTRL_PSTOPO;
+ break;
+ case STOP:
+ /* system/bus clock disabled */
+ val2 |= 0x1 << BP_PMCTRL_PSTOPO;
+ break;
+ case VLPS:
+ val2 |= 0x2 << BP_PMCTRL_STOPM;
+ break;
+ case VLLS:
+ val2 |= 0x4 << BP_PMCTRL_STOPM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel_relaxed(val1, smc1_base + PMPROT);
+ writel_relaxed(val2, smc1_base + PMCTRL);
+ writel_relaxed(val3, pmc0_base + PMC_CTRL);
+
+ return 0;
+}
+
+static struct map_desc iram_tlb_io_desc __initdata = {
+ /* .virtual and .pfn are run-time assigned */
+ .length = SZ_1M,
+ .type = MT_MEMORY_RWX_NONCACHED,
+};
+
+static const char * const low_power_ocram_match[] __initconst = {
+ "fsl,lpm-sram",
+ NULL
+};
+
+static struct map_desc imx7ulp_pm_io_desc[] __initdata = {
+ imx_map_entry(MX7ULP, AIPS1, MT_DEVICE),
+ imx_map_entry(MX7ULP, AIPS2, MT_DEVICE),
+};
+
+static int __init imx7ulp_dt_find_lpsram(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ unsigned long lpram_addr;
+ const __be32 *prop = of_get_flat_dt_prop(node, "reg", NULL);
+
+ if (of_flat_dt_match(node, low_power_ocram_match)) {
+ if (!prop)
+ return -EINVAL;
+
+ lpram_addr = be32_to_cpup(prop);
+
+ /* We need to create a 1M page table entry. */
+ iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000);
+ iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000);
+ iram_tlb_phys_addr = lpram_addr;
+ iram_tlb_base_addr = IMX_IO_P2V(lpram_addr);
+ iotable_init(&iram_tlb_io_desc, 1);
+ }
+
+ return 0;
+}
+
+void __init imx7ulp_pm_map_io(void)
+{
+ unsigned long i, j;
+
+ iotable_init(imx7ulp_pm_io_desc, ARRAY_SIZE(imx7ulp_pm_io_desc));
+ /*
+ * Get the address of IRAM or OCRAM to be used by the low
+ * power code from the device tree.
+ */
+ WARN_ON(of_scan_flat_dt(imx7ulp_dt_find_lpsram, NULL));
+
+ /* Return if no IRAM space is allocated for suspend/resume code. */
+ if (!iram_tlb_base_addr) {
+ pr_warn("No valid ocram available for suspend/resume!\n");
+ return;
+ }
+
+ /* Set all entries to 0 except first 3 words reserved for M4. */
+ memset((void *)iram_tlb_base_addr, 0, MX7ULP_IRAM_TLB_SIZE);
+
+ /*
+ * Make sure the IRAM virtual address has a mapping in the IRAM
+ * page table.
+ *
+ * Only use the top 12 bits [31-20] when storing the physical
+ * address in the page table as only these bits are required
+ * for 1M mapping.
+ */
+ j = ((iram_tlb_base_addr >> 20) << 2) / 4;
+ *((unsigned long *)iram_tlb_base_addr + j) =
+ (iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
+
+ /*
+ * Make sure the AIPS1 virtual address has a mapping in the
+ * IRAM page table.
+ */
+ for (i = 0; i < 4; i++) {
+ j = ((IMX_IO_P2V(MX7ULP_AIPS1_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
+ *((unsigned long *)iram_tlb_base_addr + j) =
+ ((MX7ULP_AIPS1_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
+ TT_ATTRIB_NON_CACHEABLE_1M;
+ }
+ /*
+ * Make sure the AIPS2 virtual address has a mapping in the
+ * IRAM page table.
+ */
+ for (i = 0; i < 4; i++) {
+ j = ((IMX_IO_P2V(MX7ULP_AIPS2_BASE_ADDR + i * 0x100000) >> 20) << 2) / 4;
+ *((unsigned long *)iram_tlb_base_addr + j) =
+ ((MX7ULP_AIPS2_BASE_ADDR + i * 0x100000) & 0xFFF00000) |
+ TT_ATTRIB_NON_CACHEABLE_1M;
+ }
+}
+
+void __init imx7ulp_pm_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1");
+ smc1_base = of_iomap(np, 0);
+ WARN_ON(!smc1_base);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pmc0");
+ pmc0_base = of_iomap(np, 0);
+ WARN_ON(!pmc0_base);
+
+ imx7ulp_set_lpm(RUN);
+}