diff options
author | Arnd Bergmann <arnd@arndb.de> | 2018-03-15 11:10:32 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2018-03-15 11:10:32 -0400 |
commit | 0240f307213e4fb238eeacbf4bc18c7a13ac4774 (patch) | |
tree | 93f6ab4617658ff9ab4fb2cb199e838c5b2bc7a4 | |
parent | 8694360b281c91b419c1eb050b53422adcef218e (diff) | |
parent | dee5dee2a5b285d20f55a4758d3a51349691eeea (diff) |
Merge tag 'imx-soc-4.17' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into next/soc
Pull "i.MX SoC changes for 4.17" from Shawn Guo:
- Add i.MX 6SoloLiteLite (i.MX6SLL) SoC support on top of the existing
i.MX6SL platform code.
- Improve the SoC revision mapping by utilizing the MAJOR field of
ANATOP DIGPROG register.
- Add CPUIDLE_FLAG_TIMER_STOP flag for cpuidle ARM power off state,
so that we can use ARM generic timer for some i.MX6 SoC.
- Set low-power interrupt mask for i.MX25 to support STOP mode.
- Drop EPIT driver as there is no user of it.
- Simplify the error path of imx6_pm_get_base() a bit.
* tag 'imx-soc-4.17' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
ARM: imx: Add basic msl support for imx6sll
ARM: imx: pm-imx6: Return the error directly
ARM: imx: avic: set low-power interrupt mask for imx25
ARM: imx: Improve the soc revision calculation flow
ARM: imx: add timer stop flag to ARM power off state
ARM: imx: Remove epit support
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 20 | ||||
-rw-r--r-- | arch/arm/mach-imx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-imx/anatop.c | 56 | ||||
-rw-r--r-- | arch/arm/mach-imx/avic.c | 37 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpu.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpuidle-imx6sl.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpuidle-imx6sx.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/epit.c | 228 | ||||
-rw-r--r-- | arch/arm/mach-imx/mach-imx6sl.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-imx/mxc.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-imx/pm-imx6.c | 7 |
11 files changed, 89 insertions, 288 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 782699e67600..f53ec31c9f5a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig | |||
@@ -32,18 +32,6 @@ config MXC_DEBUG_BOARD | |||
32 | data/address de-multiplexing and decode, signal level shift, | 32 | data/address de-multiplexing and decode, signal level shift, |
33 | interrupt control and various board functions. | 33 | interrupt control and various board functions. |
34 | 34 | ||
35 | config HAVE_EPIT | ||
36 | bool | ||
37 | |||
38 | config MXC_USE_EPIT | ||
39 | bool "Use EPIT instead of GPT" | ||
40 | depends on HAVE_EPIT | ||
41 | help | ||
42 | Use EPIT as the system timer on systems that have it. Normally you | ||
43 | don't have a reason to do so as the EPIT has the same features and | ||
44 | uses the same clocks as the GPT. Anyway, on some systems the GPT | ||
45 | may be in use for other purposes. | ||
46 | |||
47 | config HAVE_IMX_ANATOP | 35 | config HAVE_IMX_ANATOP |
48 | bool | 36 | bool |
49 | 37 | ||
@@ -85,7 +73,6 @@ config SOC_IMX31 | |||
85 | config SOC_IMX35 | 73 | config SOC_IMX35 |
86 | bool | 74 | bool |
87 | select ARCH_MXC_IOMUX_V3 | 75 | select ARCH_MXC_IOMUX_V3 |
88 | select HAVE_EPIT | ||
89 | select MXC_AVIC | 76 | select MXC_AVIC |
90 | select PINCTRL_IMX35 | 77 | select PINCTRL_IMX35 |
91 | 78 | ||
@@ -512,6 +499,13 @@ config SOC_IMX6SL | |||
512 | help | 499 | help |
513 | This enables support for Freescale i.MX6 SoloLite processor. | 500 | This enables support for Freescale i.MX6 SoloLite processor. |
514 | 501 | ||
502 | config SOC_IMX6SLL | ||
503 | bool "i.MX6 SoloLiteLite support" | ||
504 | select SOC_IMX6 | ||
505 | |||
506 | help | ||
507 | This enables support for Freescale i.MX6 SoloLiteLite processor. | ||
508 | |||
515 | config SOC_IMX6SX | 509 | config SOC_IMX6SX |
516 | bool "i.MX6 SoloX support" | 510 | bool "i.MX6 SoloX support" |
517 | select PINCTRL_IMX6SX | 511 | select PINCTRL_IMX6SX |
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 8ff71058207d..78fa86aedf34 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
@@ -20,7 +20,6 @@ obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o | |||
20 | obj-$(CONFIG_MXC_TZIC) += tzic.o | 20 | obj-$(CONFIG_MXC_TZIC) += tzic.o |
21 | obj-$(CONFIG_MXC_AVIC) += avic.o | 21 | obj-$(CONFIG_MXC_AVIC) += avic.o |
22 | 22 | ||
23 | obj-$(CONFIG_MXC_USE_EPIT) += epit.o | ||
24 | obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o | 23 | obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o |
25 | 24 | ||
26 | ifeq ($(CONFIG_CPU_IDLE),y) | 25 | ifeq ($(CONFIG_CPU_IDLE),y) |
@@ -78,6 +77,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | |||
78 | endif | 77 | endif |
79 | obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o | 78 | obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o |
80 | obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o | 79 | obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o |
80 | obj-$(CONFIG_SOC_IMX6SLL) += mach-imx6sl.o | ||
81 | obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o | 81 | obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o |
82 | obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o | 82 | obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o |
83 | obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o | 83 | obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o |
diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index 649a84c251ad..61f3d94f1633 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. | 2 | * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. |
3 | * Copyright 2017-2018 NXP. | ||
3 | * | 4 | * |
4 | * The code contained herein is licensed under the GNU General Public | 5 | * The code contained herein is licensed under the GNU General Public |
5 | * License. You may obtain a copy of the GNU General Public License | 6 | * License. You may obtain a copy of the GNU General Public License |
@@ -116,6 +117,7 @@ void __init imx_init_revision_from_anatop(void) | |||
116 | unsigned int revision; | 117 | unsigned int revision; |
117 | u32 digprog; | 118 | u32 digprog; |
118 | u16 offset = ANADIG_DIGPROG; | 119 | u16 offset = ANADIG_DIGPROG; |
120 | u8 major_part, minor_part; | ||
119 | 121 | ||
120 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); | 122 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); |
121 | anatop_base = of_iomap(np, 0); | 123 | anatop_base = of_iomap(np, 0); |
@@ -127,45 +129,25 @@ void __init imx_init_revision_from_anatop(void) | |||
127 | digprog = readl_relaxed(anatop_base + offset); | 129 | digprog = readl_relaxed(anatop_base + offset); |
128 | iounmap(anatop_base); | 130 | iounmap(anatop_base); |
129 | 131 | ||
130 | switch (digprog & 0xff) { | 132 | /* |
131 | case 0: | 133 | * On i.MX7D digprog value match linux version format, so |
132 | /* | 134 | * it needn't map again and we can use register value directly. |
133 | * For i.MX6QP, most of the code for i.MX6Q can be resued, | 135 | */ |
134 | * so internally, we identify it as i.MX6Q Rev 2.0 | 136 | if (of_device_is_compatible(np, "fsl,imx7d-anatop")) { |
135 | */ | 137 | revision = digprog & 0xff; |
136 | if (digprog >> 8 & 0x01) | 138 | } else { |
137 | revision = IMX_CHIP_REVISION_2_0; | ||
138 | else | ||
139 | revision = IMX_CHIP_REVISION_1_0; | ||
140 | break; | ||
141 | case 1: | ||
142 | revision = IMX_CHIP_REVISION_1_1; | ||
143 | break; | ||
144 | case 2: | ||
145 | revision = IMX_CHIP_REVISION_1_2; | ||
146 | break; | ||
147 | case 3: | ||
148 | revision = IMX_CHIP_REVISION_1_3; | ||
149 | break; | ||
150 | case 4: | ||
151 | revision = IMX_CHIP_REVISION_1_4; | ||
152 | break; | ||
153 | case 5: | ||
154 | /* | ||
155 | * i.MX6DQ TO1.5 is defined as Rev 1.3 in Data Sheet, marked | ||
156 | * as 'D' in Part Number last character. | ||
157 | */ | ||
158 | revision = IMX_CHIP_REVISION_1_5; | ||
159 | break; | ||
160 | default: | ||
161 | /* | 139 | /* |
162 | * Fail back to return raw register value instead of 0xff. | 140 | * MAJOR: [15:8], the major silicon revison; |
163 | * It will be easy to know version information in SOC if it | 141 | * MINOR: [7: 0], the minor silicon revison; |
164 | * can't be recognized by known version. And some chip's (i.MX7D) | 142 | * |
165 | * digprog value match linux version format, so it needn't map | 143 | * please refer to the i.MX RM for the detailed |
166 | * again and we can use register value directly. | 144 | * silicon revison bit define. |
145 | * format the major part and minor part to match the | ||
146 | * linux kernel soc version format. | ||
167 | */ | 147 | */ |
168 | revision = digprog & 0xff; | 148 | major_part = (digprog >> 8) & 0xf; |
149 | minor_part = digprog & 0xf; | ||
150 | revision = ((major_part + 1) << 4) | minor_part; | ||
169 | } | 151 | } |
170 | 152 | ||
171 | mxc_set_cpu_type(digprog >> 16 & 0xff); | 153 | mxc_set_cpu_type(digprog >> 16 & 0xff); |
diff --git a/arch/arm/mach-imx/avic.c b/arch/arm/mach-imx/avic.c index 1afccae0420c..c0434a36687a 100644 --- a/arch/arm/mach-imx/avic.c +++ b/arch/arm/mach-imx/avic.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/irqdomain.h> | 22 | #include <linux/irqdomain.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/of_address.h> | ||
25 | #include <asm/mach/irq.h> | 26 | #include <asm/mach/irq.h> |
26 | #include <asm/exception.h> | 27 | #include <asm/exception.h> |
27 | 28 | ||
@@ -51,7 +52,12 @@ | |||
51 | 52 | ||
52 | #define AVIC_NUM_IRQS 64 | 53 | #define AVIC_NUM_IRQS 64 |
53 | 54 | ||
55 | /* low power interrupt mask registers */ | ||
56 | #define MX25_CCM_LPIMR0 0x68 | ||
57 | #define MX25_CCM_LPIMR1 0x6C | ||
58 | |||
54 | static void __iomem *avic_base; | 59 | static void __iomem *avic_base; |
60 | static void __iomem *mx25_ccm_base; | ||
55 | static struct irq_domain *domain; | 61 | static struct irq_domain *domain; |
56 | 62 | ||
57 | #ifdef CONFIG_FIQ | 63 | #ifdef CONFIG_FIQ |
@@ -93,6 +99,18 @@ static void avic_irq_suspend(struct irq_data *d) | |||
93 | 99 | ||
94 | avic_saved_mask_reg[idx] = imx_readl(avic_base + ct->regs.mask); | 100 | avic_saved_mask_reg[idx] = imx_readl(avic_base + ct->regs.mask); |
95 | imx_writel(gc->wake_active, avic_base + ct->regs.mask); | 101 | imx_writel(gc->wake_active, avic_base + ct->regs.mask); |
102 | |||
103 | if (mx25_ccm_base) { | ||
104 | u8 offs = d->hwirq < AVIC_NUM_IRQS / 2 ? | ||
105 | MX25_CCM_LPIMR0 : MX25_CCM_LPIMR1; | ||
106 | /* | ||
107 | * The interrupts which are still enabled will be used as wakeup | ||
108 | * sources. Allow those interrupts in low-power mode. | ||
109 | * The LPIMR registers use 0 to allow an interrupt, the AVIC | ||
110 | * registers use 1. | ||
111 | */ | ||
112 | imx_writel(~gc->wake_active, mx25_ccm_base + offs); | ||
113 | } | ||
96 | } | 114 | } |
97 | 115 | ||
98 | static void avic_irq_resume(struct irq_data *d) | 116 | static void avic_irq_resume(struct irq_data *d) |
@@ -102,6 +120,13 @@ static void avic_irq_resume(struct irq_data *d) | |||
102 | int idx = d->hwirq >> 5; | 120 | int idx = d->hwirq >> 5; |
103 | 121 | ||
104 | imx_writel(avic_saved_mask_reg[idx], avic_base + ct->regs.mask); | 122 | imx_writel(avic_saved_mask_reg[idx], avic_base + ct->regs.mask); |
123 | |||
124 | if (mx25_ccm_base) { | ||
125 | u8 offs = d->hwirq < AVIC_NUM_IRQS / 2 ? | ||
126 | MX25_CCM_LPIMR0 : MX25_CCM_LPIMR1; | ||
127 | |||
128 | imx_writel(0xffffffff, mx25_ccm_base + offs); | ||
129 | } | ||
105 | } | 130 | } |
106 | 131 | ||
107 | #else | 132 | #else |
@@ -158,6 +183,18 @@ void __init mxc_init_irq(void __iomem *irqbase) | |||
158 | 183 | ||
159 | avic_base = irqbase; | 184 | avic_base = irqbase; |
160 | 185 | ||
186 | np = of_find_compatible_node(NULL, NULL, "fsl,imx25-ccm"); | ||
187 | mx25_ccm_base = of_iomap(np, 0); | ||
188 | |||
189 | if (mx25_ccm_base) { | ||
190 | /* | ||
191 | * By default, we mask all interrupts. We set the actual mask | ||
192 | * before we go into low-power mode. | ||
193 | */ | ||
194 | imx_writel(0xffffffff, mx25_ccm_base + MX25_CCM_LPIMR0); | ||
195 | imx_writel(0xffffffff, mx25_ccm_base + MX25_CCM_LPIMR1); | ||
196 | } | ||
197 | |||
161 | /* put the AVIC into the reset value with | 198 | /* put the AVIC into the reset value with |
162 | * all interrupts disabled | 199 | * all interrupts disabled |
163 | */ | 200 | */ |
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index d4e55f2a897e..32969f34486a 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c | |||
@@ -135,6 +135,9 @@ struct device * __init imx_soc_device_init(void) | |||
135 | case MXC_CPU_IMX6ULL: | 135 | case MXC_CPU_IMX6ULL: |
136 | soc_id = "i.MX6ULL"; | 136 | soc_id = "i.MX6ULL"; |
137 | break; | 137 | break; |
138 | case MXC_CPU_IMX6SLL: | ||
139 | soc_id = "i.MX6SLL"; | ||
140 | break; | ||
138 | case MXC_CPU_IMX7D: | 141 | case MXC_CPU_IMX7D: |
139 | soc_id = "i.MX7D"; | 142 | soc_id = "i.MX7D"; |
140 | break; | 143 | break; |
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c index 8d866fb674a8..fa8ead145d17 100644 --- a/arch/arm/mach-imx/cpuidle-imx6sl.c +++ b/arch/arm/mach-imx/cpuidle-imx6sl.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include "common.h" | 13 | #include "common.h" |
14 | #include "cpuidle.h" | 14 | #include "cpuidle.h" |
15 | #include "hardware.h" | ||
15 | 16 | ||
16 | static int imx6sl_enter_wait(struct cpuidle_device *dev, | 17 | static int imx6sl_enter_wait(struct cpuidle_device *dev, |
17 | struct cpuidle_driver *drv, int index) | 18 | struct cpuidle_driver *drv, int index) |
@@ -21,9 +22,11 @@ static int imx6sl_enter_wait(struct cpuidle_device *dev, | |||
21 | * Software workaround for ERR005311, see function | 22 | * Software workaround for ERR005311, see function |
22 | * description for details. | 23 | * description for details. |
23 | */ | 24 | */ |
24 | imx6sl_set_wait_clk(true); | 25 | if (cpu_is_imx6sl()) |
26 | imx6sl_set_wait_clk(true); | ||
25 | cpu_do_idle(); | 27 | cpu_do_idle(); |
26 | imx6sl_set_wait_clk(false); | 28 | if (cpu_is_imx6sl()) |
29 | imx6sl_set_wait_clk(false); | ||
27 | imx6_set_lpm(WAIT_CLOCKED); | 30 | imx6_set_lpm(WAIT_CLOCKED); |
28 | 31 | ||
29 | return index; | 32 | return index; |
diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c index c5a5c3a70ab1..d0f14b761ff7 100644 --- a/arch/arm/mach-imx/cpuidle-imx6sx.c +++ b/arch/arm/mach-imx/cpuidle-imx6sx.c | |||
@@ -89,6 +89,7 @@ static struct cpuidle_driver imx6sx_cpuidle_driver = { | |||
89 | */ | 89 | */ |
90 | .exit_latency = 300, | 90 | .exit_latency = 300, |
91 | .target_residency = 500, | 91 | .target_residency = 500, |
92 | .flags = CPUIDLE_FLAG_TIMER_STOP, | ||
92 | .enter = imx6sx_enter_wait, | 93 | .enter = imx6sx_enter_wait, |
93 | .name = "LOW-POWER-IDLE", | 94 | .name = "LOW-POWER-IDLE", |
94 | .desc = "ARM power off", | 95 | .desc = "ARM power off", |
diff --git a/arch/arm/mach-imx/epit.c b/arch/arm/mach-imx/epit.c deleted file mode 100644 index fb9a73a57d00..000000000000 --- a/arch/arm/mach-imx/epit.c +++ /dev/null | |||
@@ -1,228 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-mxc/epit.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
18 | * MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #define EPITCR 0x00 | ||
22 | #define EPITSR 0x04 | ||
23 | #define EPITLR 0x08 | ||
24 | #define EPITCMPR 0x0c | ||
25 | #define EPITCNR 0x10 | ||
26 | |||
27 | #define EPITCR_EN (1 << 0) | ||
28 | #define EPITCR_ENMOD (1 << 1) | ||
29 | #define EPITCR_OCIEN (1 << 2) | ||
30 | #define EPITCR_RLD (1 << 3) | ||
31 | #define EPITCR_PRESC(x) (((x) & 0xfff) << 4) | ||
32 | #define EPITCR_SWR (1 << 16) | ||
33 | #define EPITCR_IOVW (1 << 17) | ||
34 | #define EPITCR_DBGEN (1 << 18) | ||
35 | #define EPITCR_WAITEN (1 << 19) | ||
36 | #define EPITCR_RES (1 << 20) | ||
37 | #define EPITCR_STOPEN (1 << 21) | ||
38 | #define EPITCR_OM_DISCON (0 << 22) | ||
39 | #define EPITCR_OM_TOGGLE (1 << 22) | ||
40 | #define EPITCR_OM_CLEAR (2 << 22) | ||
41 | #define EPITCR_OM_SET (3 << 22) | ||
42 | #define EPITCR_CLKSRC_OFF (0 << 24) | ||
43 | #define EPITCR_CLKSRC_PERIPHERAL (1 << 24) | ||
44 | #define EPITCR_CLKSRC_REF_HIGH (1 << 24) | ||
45 | #define EPITCR_CLKSRC_REF_LOW (3 << 24) | ||
46 | |||
47 | #define EPITSR_OCIF (1 << 0) | ||
48 | |||
49 | #include <linux/interrupt.h> | ||
50 | #include <linux/irq.h> | ||
51 | #include <linux/clockchips.h> | ||
52 | #include <linux/clk.h> | ||
53 | #include <linux/err.h> | ||
54 | #include <asm/mach/time.h> | ||
55 | |||
56 | #include "common.h" | ||
57 | #include "hardware.h" | ||
58 | |||
59 | static struct clock_event_device clockevent_epit; | ||
60 | |||
61 | static void __iomem *timer_base; | ||
62 | |||
63 | static inline void epit_irq_disable(void) | ||
64 | { | ||
65 | u32 val; | ||
66 | |||
67 | val = imx_readl(timer_base + EPITCR); | ||
68 | val &= ~EPITCR_OCIEN; | ||
69 | imx_writel(val, timer_base + EPITCR); | ||
70 | } | ||
71 | |||
72 | static inline void epit_irq_enable(void) | ||
73 | { | ||
74 | u32 val; | ||
75 | |||
76 | val = imx_readl(timer_base + EPITCR); | ||
77 | val |= EPITCR_OCIEN; | ||
78 | imx_writel(val, timer_base + EPITCR); | ||
79 | } | ||
80 | |||
81 | static void epit_irq_acknowledge(void) | ||
82 | { | ||
83 | imx_writel(EPITSR_OCIF, timer_base + EPITSR); | ||
84 | } | ||
85 | |||
86 | static int __init epit_clocksource_init(struct clk *timer_clk) | ||
87 | { | ||
88 | unsigned int c = clk_get_rate(timer_clk); | ||
89 | |||
90 | return clocksource_mmio_init(timer_base + EPITCNR, "epit", c, 200, 32, | ||
91 | clocksource_mmio_readl_down); | ||
92 | } | ||
93 | |||
94 | /* clock event */ | ||
95 | |||
96 | static int epit_set_next_event(unsigned long evt, | ||
97 | struct clock_event_device *unused) | ||
98 | { | ||
99 | unsigned long tcmp; | ||
100 | |||
101 | tcmp = imx_readl(timer_base + EPITCNR); | ||
102 | |||
103 | imx_writel(tcmp - evt, timer_base + EPITCMPR); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | /* Left event sources disabled, no more interrupts appear */ | ||
109 | static int epit_shutdown(struct clock_event_device *evt) | ||
110 | { | ||
111 | unsigned long flags; | ||
112 | |||
113 | /* | ||
114 | * The timer interrupt generation is disabled at least | ||
115 | * for enough time to call epit_set_next_event() | ||
116 | */ | ||
117 | local_irq_save(flags); | ||
118 | |||
119 | /* Disable interrupt in GPT module */ | ||
120 | epit_irq_disable(); | ||
121 | |||
122 | /* Clear pending interrupt */ | ||
123 | epit_irq_acknowledge(); | ||
124 | |||
125 | local_irq_restore(flags); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int epit_set_oneshot(struct clock_event_device *evt) | ||
131 | { | ||
132 | unsigned long flags; | ||
133 | |||
134 | /* | ||
135 | * The timer interrupt generation is disabled at least | ||
136 | * for enough time to call epit_set_next_event() | ||
137 | */ | ||
138 | local_irq_save(flags); | ||
139 | |||
140 | /* Disable interrupt in GPT module */ | ||
141 | epit_irq_disable(); | ||
142 | |||
143 | /* Clear pending interrupt, only while switching mode */ | ||
144 | if (!clockevent_state_oneshot(evt)) | ||
145 | epit_irq_acknowledge(); | ||
146 | |||
147 | /* | ||
148 | * Do not put overhead of interrupt enable/disable into | ||
149 | * epit_set_next_event(), the core has about 4 minutes | ||
150 | * to call epit_set_next_event() or shutdown clock after | ||
151 | * mode switching | ||
152 | */ | ||
153 | epit_irq_enable(); | ||
154 | local_irq_restore(flags); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * IRQ handler for the timer | ||
161 | */ | ||
162 | static irqreturn_t epit_timer_interrupt(int irq, void *dev_id) | ||
163 | { | ||
164 | struct clock_event_device *evt = &clockevent_epit; | ||
165 | |||
166 | epit_irq_acknowledge(); | ||
167 | |||
168 | evt->event_handler(evt); | ||
169 | |||
170 | return IRQ_HANDLED; | ||
171 | } | ||
172 | |||
173 | static struct irqaction epit_timer_irq = { | ||
174 | .name = "i.MX EPIT Timer Tick", | ||
175 | .flags = IRQF_TIMER | IRQF_IRQPOLL, | ||
176 | .handler = epit_timer_interrupt, | ||
177 | }; | ||
178 | |||
179 | static struct clock_event_device clockevent_epit = { | ||
180 | .name = "epit", | ||
181 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
182 | .set_state_shutdown = epit_shutdown, | ||
183 | .tick_resume = epit_shutdown, | ||
184 | .set_state_oneshot = epit_set_oneshot, | ||
185 | .set_next_event = epit_set_next_event, | ||
186 | .rating = 200, | ||
187 | }; | ||
188 | |||
189 | static int __init epit_clockevent_init(struct clk *timer_clk) | ||
190 | { | ||
191 | clockevent_epit.cpumask = cpumask_of(0); | ||
192 | clockevents_config_and_register(&clockevent_epit, | ||
193 | clk_get_rate(timer_clk), | ||
194 | 0x800, 0xfffffffe); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | void __init epit_timer_init(void __iomem *base, int irq) | ||
200 | { | ||
201 | struct clk *timer_clk; | ||
202 | |||
203 | timer_clk = clk_get_sys("imx-epit.0", NULL); | ||
204 | if (IS_ERR(timer_clk)) { | ||
205 | pr_err("i.MX epit: unable to get clk\n"); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | clk_prepare_enable(timer_clk); | ||
210 | |||
211 | timer_base = base; | ||
212 | |||
213 | /* | ||
214 | * Initialise to a known state (all timers off, and timing reset) | ||
215 | */ | ||
216 | imx_writel(0x0, timer_base + EPITCR); | ||
217 | |||
218 | imx_writel(0xffffffff, timer_base + EPITLR); | ||
219 | imx_writel(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN, | ||
220 | timer_base + EPITCR); | ||
221 | |||
222 | /* init and register the timer to the framework */ | ||
223 | epit_clocksource_init(timer_clk); | ||
224 | epit_clockevent_init(timer_clk); | ||
225 | |||
226 | /* Make irqs happen */ | ||
227 | setup_irq(irq, &epit_timer_irq); | ||
228 | } | ||
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index 04084900d810..c7a1ef180dda 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "cpuidle.h" | 20 | #include "cpuidle.h" |
21 | #include "hardware.h" | ||
21 | 22 | ||
22 | static void __init imx6sl_fec_init(void) | 23 | static void __init imx6sl_fec_init(void) |
23 | { | 24 | { |
@@ -54,7 +55,8 @@ static void __init imx6sl_init_machine(void) | |||
54 | 55 | ||
55 | of_platform_default_populate(NULL, NULL, parent); | 56 | of_platform_default_populate(NULL, NULL, parent); |
56 | 57 | ||
57 | imx6sl_fec_init(); | 58 | if (cpu_is_imx6sl()) |
59 | imx6sl_fec_init(); | ||
58 | imx_anatop_init(); | 60 | imx_anatop_init(); |
59 | imx6sl_pm_init(); | 61 | imx6sl_pm_init(); |
60 | } | 62 | } |
@@ -66,11 +68,15 @@ static void __init imx6sl_init_irq(void) | |||
66 | imx_init_l2cache(); | 68 | imx_init_l2cache(); |
67 | imx_src_init(); | 69 | imx_src_init(); |
68 | irqchip_init(); | 70 | irqchip_init(); |
69 | imx6_pm_ccm_init("fsl,imx6sl-ccm"); | 71 | if (cpu_is_imx6sl()) |
72 | imx6_pm_ccm_init("fsl,imx6sl-ccm"); | ||
73 | else | ||
74 | imx6_pm_ccm_init("fsl,imx6sll-ccm"); | ||
70 | } | 75 | } |
71 | 76 | ||
72 | static const char * const imx6sl_dt_compat[] __initconst = { | 77 | static const char * const imx6sl_dt_compat[] __initconst = { |
73 | "fsl,imx6sl", | 78 | "fsl,imx6sl", |
79 | "fsl,imx6sll", | ||
74 | NULL, | 80 | NULL, |
75 | }; | 81 | }; |
76 | 82 | ||
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index e00d6260c3df..026e2ca45f1e 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #define MXC_CPU_IMX6Q 0x63 | 40 | #define MXC_CPU_IMX6Q 0x63 |
41 | #define MXC_CPU_IMX6UL 0x64 | 41 | #define MXC_CPU_IMX6UL 0x64 |
42 | #define MXC_CPU_IMX6ULL 0x65 | 42 | #define MXC_CPU_IMX6ULL 0x65 |
43 | #define MXC_CPU_IMX6SLL 0x67 | ||
43 | #define MXC_CPU_IMX7D 0x72 | 44 | #define MXC_CPU_IMX7D 0x72 |
44 | 45 | ||
45 | #define IMX_DDR_TYPE_LPDDR2 1 | 46 | #define IMX_DDR_TYPE_LPDDR2 1 |
@@ -79,6 +80,11 @@ static inline bool cpu_is_imx6ull(void) | |||
79 | return __mxc_cpu_type == MXC_CPU_IMX6ULL; | 80 | return __mxc_cpu_type == MXC_CPU_IMX6ULL; |
80 | } | 81 | } |
81 | 82 | ||
83 | static inline bool cpu_is_imx6sll(void) | ||
84 | { | ||
85 | return __mxc_cpu_type == MXC_CPU_IMX6SLL; | ||
86 | } | ||
87 | |||
82 | static inline bool cpu_is_imx6q(void) | 88 | static inline bool cpu_is_imx6q(void) |
83 | { | 89 | { |
84 | return __mxc_cpu_type == MXC_CPU_IMX6Q; | 90 | return __mxc_cpu_type == MXC_CPU_IMX6Q; |
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index ecdf071653d4..017539dd712b 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c | |||
@@ -428,10 +428,8 @@ static int __init imx6_pm_get_base(struct imx6_pm_base *base, | |||
428 | int ret = 0; | 428 | int ret = 0; |
429 | 429 | ||
430 | node = of_find_compatible_node(NULL, NULL, compat); | 430 | node = of_find_compatible_node(NULL, NULL, compat); |
431 | if (!node) { | 431 | if (!node) |
432 | ret = -ENODEV; | 432 | return -ENODEV; |
433 | goto out; | ||
434 | } | ||
435 | 433 | ||
436 | ret = of_address_to_resource(node, 0, &res); | 434 | ret = of_address_to_resource(node, 0, &res); |
437 | if (ret) | 435 | if (ret) |
@@ -444,7 +442,6 @@ static int __init imx6_pm_get_base(struct imx6_pm_base *base, | |||
444 | 442 | ||
445 | put_node: | 443 | put_node: |
446 | of_node_put(node); | 444 | of_node_put(node); |
447 | out: | ||
448 | return ret; | 445 | return ret; |
449 | } | 446 | } |
450 | 447 | ||