diff options
author | Anson Huang <Anson.Huang@nxp.com> | 2016-11-08 00:06:50 +0800 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:25:13 +0800 |
commit | 209f156a568f33ea84664b5d051405ffe909db51 (patch) | |
tree | 1986cdccce9b789788c408fb55308c7f45343511 | |
parent | 37e61480a1efa88fb7c5e3387dcad35b250e4008 (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/Kconfig | 13 | ||||
-rw-r--r-- | arch/arm/mach-imx/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/common.h | 14 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpu.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-imx/hardware.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/mach-imx7ulp.c | 58 | ||||
-rw-r--r-- | arch/arm/mach-imx/mx7ulp.h | 36 | ||||
-rw-r--r-- | arch/arm/mach-imx/mxc.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-imx/pm-imx7ulp.c | 232 |
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); +} |