diff options
Diffstat (limited to 'arch/arm/mach-imx')
29 files changed, 1338 insertions, 503 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 33567aa5880f..5740296dc429 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig | |||
@@ -1,19 +1,15 @@ | |||
1 | config ARCH_MXC | 1 | config ARCH_MXC |
2 | bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 | 2 | bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 |
3 | select ARCH_HAS_CPUFREQ | ||
4 | select ARCH_HAS_OPP | ||
3 | select ARCH_REQUIRE_GPIOLIB | 5 | select ARCH_REQUIRE_GPIOLIB |
4 | select ARM_CPU_SUSPEND if PM | 6 | select ARM_CPU_SUSPEND if PM |
5 | select ARM_PATCH_PHYS_VIRT | ||
6 | select CLKSRC_MMIO | 7 | select CLKSRC_MMIO |
7 | select COMMON_CLK | ||
8 | select GENERIC_ALLOCATOR | ||
9 | select GENERIC_CLOCKEVENTS | ||
10 | select GENERIC_IRQ_CHIP | 8 | select GENERIC_IRQ_CHIP |
11 | select MIGHT_HAVE_CACHE_L2X0 if ARCH_MULTI_V6_V7 | ||
12 | select MULTI_IRQ_HANDLER | ||
13 | select PINCTRL | 9 | select PINCTRL |
10 | select PM_OPP if PM | ||
14 | select SOC_BUS | 11 | select SOC_BUS |
15 | select SPARSE_IRQ | 12 | select SRAM |
16 | select USE_OF | ||
17 | help | 13 | help |
18 | Support for Freescale MXC/iMX-based family of processors | 14 | Support for Freescale MXC/iMX-based family of processors |
19 | 15 | ||
@@ -121,18 +117,16 @@ config SOC_IMX31 | |||
121 | config SOC_IMX35 | 117 | config SOC_IMX35 |
122 | bool | 118 | bool |
123 | select ARCH_MXC_IOMUX_V3 | 119 | select ARCH_MXC_IOMUX_V3 |
124 | select CPU_V6K | ||
125 | select HAVE_EPIT | 120 | select HAVE_EPIT |
126 | select MXC_AVIC | 121 | select MXC_AVIC |
122 | select PINCTRL_IMX35 | ||
127 | select SMP_ON_UP if SMP | 123 | select SMP_ON_UP if SMP |
128 | select PINCTRL | ||
129 | 124 | ||
130 | config SOC_IMX5 | 125 | config SOC_IMX5 |
131 | bool | 126 | bool |
132 | select ARCH_HAS_CPUFREQ | 127 | select ARCH_HAS_CPUFREQ |
133 | select ARCH_HAS_OPP | 128 | select ARCH_HAS_OPP |
134 | select ARCH_MXC_IOMUX_V3 | 129 | select ARCH_MXC_IOMUX_V3 |
135 | select CPU_V7 | ||
136 | select MXC_TZIC | 130 | select MXC_TZIC |
137 | 131 | ||
138 | config SOC_IMX51 | 132 | config SOC_IMX51 |
@@ -777,65 +771,50 @@ config SOC_IMX50 | |||
777 | config SOC_IMX53 | 771 | config SOC_IMX53 |
778 | bool "i.MX53 support" | 772 | bool "i.MX53 support" |
779 | select HAVE_IMX_SRC | 773 | select HAVE_IMX_SRC |
780 | select IMX_HAVE_PLATFORM_IMX2_WDT | ||
781 | select PINCTRL_IMX53 | 774 | select PINCTRL_IMX53 |
782 | select SOC_IMX5 | 775 | select SOC_IMX5 |
783 | 776 | ||
784 | help | 777 | help |
785 | This enables support for Freescale i.MX53 processor. | 778 | This enables support for Freescale i.MX53 processor. |
786 | 779 | ||
787 | config SOC_IMX6Q | 780 | config SOC_IMX6 |
788 | bool "i.MX6 Quad/DualLite support" | 781 | bool |
789 | select ARCH_HAS_CPUFREQ | ||
790 | select ARCH_HAS_OPP | ||
791 | select ARM_ERRATA_754322 | 782 | select ARM_ERRATA_754322 |
792 | select ARM_ERRATA_764369 if SMP | ||
793 | select ARM_ERRATA_775420 | 783 | select ARM_ERRATA_775420 |
794 | select ARM_GIC | 784 | select ARM_GIC |
795 | select CPU_V7 | ||
796 | select HAVE_ARM_SCU if SMP | ||
797 | select HAVE_ARM_TWD if SMP | ||
798 | select HAVE_IMX_ANATOP | 785 | select HAVE_IMX_ANATOP |
799 | select HAVE_IMX_GPC | 786 | select HAVE_IMX_GPC |
800 | select HAVE_IMX_MMDC | 787 | select HAVE_IMX_MMDC |
801 | select HAVE_IMX_SRC | 788 | select HAVE_IMX_SRC |
802 | select HAVE_SMP | ||
803 | select MFD_SYSCON | 789 | select MFD_SYSCON |
804 | select MIGHT_HAVE_PCI | ||
805 | select PCI_DOMAINS if PCI | ||
806 | select PINCTRL_IMX6Q | ||
807 | select PL310_ERRATA_588369 if CACHE_PL310 | 790 | select PL310_ERRATA_588369 if CACHE_PL310 |
808 | select PL310_ERRATA_727915 if CACHE_PL310 | 791 | select PL310_ERRATA_727915 if CACHE_PL310 |
809 | select PL310_ERRATA_769419 if CACHE_PL310 | 792 | select PL310_ERRATA_769419 if CACHE_PL310 |
810 | select PM_OPP if PM | 793 | |
794 | config SOC_IMX6Q | ||
795 | bool "i.MX6 Quad/DualLite support" | ||
796 | select ARM_ERRATA_764369 if SMP | ||
797 | select HAVE_ARM_SCU if SMP | ||
798 | select HAVE_ARM_TWD if SMP | ||
799 | select MIGHT_HAVE_PCI | ||
800 | select PCI_DOMAINS if PCI | ||
801 | select PINCTRL_IMX6Q | ||
802 | select SOC_IMX6 | ||
811 | 803 | ||
812 | help | 804 | help |
813 | This enables support for Freescale i.MX6 Quad processor. | 805 | This enables support for Freescale i.MX6 Quad processor. |
814 | 806 | ||
815 | config SOC_IMX6SL | 807 | config SOC_IMX6SL |
816 | bool "i.MX6 SoloLite support" | 808 | bool "i.MX6 SoloLite support" |
817 | select ARM_ERRATA_754322 | ||
818 | select ARM_ERRATA_775420 | ||
819 | select ARM_GIC | ||
820 | select CPU_V7 | ||
821 | select HAVE_IMX_ANATOP | ||
822 | select HAVE_IMX_GPC | ||
823 | select HAVE_IMX_MMDC | ||
824 | select HAVE_IMX_SRC | ||
825 | select MFD_SYSCON | ||
826 | select PINCTRL_IMX6SL | 809 | select PINCTRL_IMX6SL |
827 | select PL310_ERRATA_588369 if CACHE_PL310 | 810 | select SOC_IMX6 |
828 | select PL310_ERRATA_727915 if CACHE_PL310 | ||
829 | select PL310_ERRATA_769419 if CACHE_PL310 | ||
830 | 811 | ||
831 | help | 812 | help |
832 | This enables support for Freescale i.MX6 SoloLite processor. | 813 | This enables support for Freescale i.MX6 SoloLite processor. |
833 | 814 | ||
834 | config SOC_VF610 | 815 | config SOC_VF610 |
835 | bool "Vybrid Family VF610 support" | 816 | bool "Vybrid Family VF610 support" |
836 | select CPU_V7 | ||
837 | select ARM_GIC | 817 | select ARM_GIC |
838 | select CLKSRC_OF | ||
839 | select PINCTRL_VF610 | 818 | select PINCTRL_VF610 |
840 | select VF_PIT_TIMER | 819 | select VF_PIT_TIMER |
841 | select PL310_ERRATA_588369 if CACHE_PL310 | 820 | select PL310_ERRATA_588369 if CACHE_PL310 |
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index ec419649320f..f4ed83032dd0 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
@@ -30,6 +30,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o | |||
30 | ifeq ($(CONFIG_CPU_IDLE),y) | 30 | ifeq ($(CONFIG_CPU_IDLE),y) |
31 | obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o | 31 | obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o |
32 | obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o | 32 | obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o |
33 | obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o | ||
33 | endif | 34 | endif |
34 | 35 | ||
35 | ifdef CONFIG_SND_IMX_SOC | 36 | ifdef CONFIG_SND_IMX_SOC |
@@ -101,9 +102,11 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | |||
101 | obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o | 102 | obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o |
102 | obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o | 103 | obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o |
103 | 104 | ||
104 | obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o | 105 | ifeq ($(CONFIG_SUSPEND),y) |
105 | # i.MX6SL reuses i.MX6Q code | 106 | AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a |
106 | obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o | 107 | obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o |
108 | endif | ||
109 | obj-$(CONFIG_SOC_IMX6) += pm-imx6.o | ||
107 | 110 | ||
108 | # i.MX5 based machines | 111 | # i.MX5 based machines |
109 | obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o | 112 | obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o |
diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c index d7ed66091a2a..bdc2e4630a08 100644 --- a/arch/arm/mach-imx/clk-imx21.c +++ b/arch/arm/mach-imx/clk-imx21.c | |||
@@ -149,7 +149,6 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href) | |||
149 | clk_register_clkdev(clk[per1], "per", "imx-gpt.1"); | 149 | clk_register_clkdev(clk[per1], "per", "imx-gpt.1"); |
150 | clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2"); | 150 | clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2"); |
151 | clk_register_clkdev(clk[per1], "per", "imx-gpt.2"); | 151 | clk_register_clkdev(clk[per1], "per", "imx-gpt.2"); |
152 | clk_register_clkdev(clk[pwm_ipg_gate], "pwm", "mxc_pwm.0"); | ||
153 | clk_register_clkdev(clk[per2], "per", "imx21-cspi.0"); | 152 | clk_register_clkdev(clk[per2], "per", "imx21-cspi.0"); |
154 | clk_register_clkdev(clk[cspi1_ipg_gate], "ipg", "imx21-cspi.0"); | 153 | clk_register_clkdev(clk[cspi1_ipg_gate], "ipg", "imx21-cspi.0"); |
155 | clk_register_clkdev(clk[per2], "per", "imx21-cspi.1"); | 154 | clk_register_clkdev(clk[per2], "per", "imx21-cspi.1"); |
diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c index 69858c78f40d..dc36e6c2f1da 100644 --- a/arch/arm/mach-imx/clk-imx25.c +++ b/arch/arm/mach-imx/clk-imx25.c | |||
@@ -265,14 +265,6 @@ int __init mx25_clocks_init(void) | |||
265 | clk_register_clkdev(clk[cspi1_ipg], NULL, "imx35-cspi.0"); | 265 | clk_register_clkdev(clk[cspi1_ipg], NULL, "imx35-cspi.0"); |
266 | clk_register_clkdev(clk[cspi2_ipg], NULL, "imx35-cspi.1"); | 266 | clk_register_clkdev(clk[cspi2_ipg], NULL, "imx35-cspi.1"); |
267 | clk_register_clkdev(clk[cspi3_ipg], NULL, "imx35-cspi.2"); | 267 | clk_register_clkdev(clk[cspi3_ipg], NULL, "imx35-cspi.2"); |
268 | clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.0"); | ||
269 | clk_register_clkdev(clk[per10], "per", "mxc_pwm.0"); | ||
270 | clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.1"); | ||
271 | clk_register_clkdev(clk[per10], "per", "mxc_pwm.1"); | ||
272 | clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.2"); | ||
273 | clk_register_clkdev(clk[per10], "per", "mxc_pwm.2"); | ||
274 | clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.3"); | ||
275 | clk_register_clkdev(clk[per10], "per", "mxc_pwm.3"); | ||
276 | clk_register_clkdev(clk[kpp_ipg], NULL, "imx-keypad"); | 268 | clk_register_clkdev(clk[kpp_ipg], NULL, "imx-keypad"); |
277 | clk_register_clkdev(clk[tsc_ipg], NULL, "mx25-adc"); | 269 | clk_register_clkdev(clk[tsc_ipg], NULL, "mx25-adc"); |
278 | clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx21-i2c.0"); | 270 | clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx21-i2c.0"); |
diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index c6b40f386786..d2da8908b268 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c | |||
@@ -231,7 +231,6 @@ int __init mx27_clocks_init(unsigned long fref) | |||
231 | clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.4"); | 231 | clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.4"); |
232 | clk_register_clkdev(clk[gpt6_ipg_gate], "ipg", "imx-gpt.5"); | 232 | clk_register_clkdev(clk[gpt6_ipg_gate], "ipg", "imx-gpt.5"); |
233 | clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.5"); | 233 | clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.5"); |
234 | clk_register_clkdev(clk[pwm_ipg_gate], NULL, "mxc_pwm.0"); | ||
235 | clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.0"); | 234 | clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.0"); |
236 | clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "imx21-mmc.0"); | 235 | clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "imx21-mmc.0"); |
237 | clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.1"); | 236 | clk_register_clkdev(clk[per2_gate], "per", "imx21-mmc.1"); |
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 19fca1fdc6fe..568ef0a4de84 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c | |||
@@ -266,8 +266,6 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil, | |||
266 | clk_register_clkdev(clk[IMX5_CLK_ECSPI2_PER_GATE], "per", "imx51-ecspi.1"); | 266 | clk_register_clkdev(clk[IMX5_CLK_ECSPI2_PER_GATE], "per", "imx51-ecspi.1"); |
267 | clk_register_clkdev(clk[IMX5_CLK_ECSPI2_IPG_GATE], "ipg", "imx51-ecspi.1"); | 267 | clk_register_clkdev(clk[IMX5_CLK_ECSPI2_IPG_GATE], "ipg", "imx51-ecspi.1"); |
268 | clk_register_clkdev(clk[IMX5_CLK_CSPI_IPG_GATE], NULL, "imx35-cspi.2"); | 268 | clk_register_clkdev(clk[IMX5_CLK_CSPI_IPG_GATE], NULL, "imx35-cspi.2"); |
269 | clk_register_clkdev(clk[IMX5_CLK_PWM1_IPG_GATE], "pwm", "mxc_pwm.0"); | ||
270 | clk_register_clkdev(clk[IMX5_CLK_PWM2_IPG_GATE], "pwm", "mxc_pwm.1"); | ||
271 | clk_register_clkdev(clk[IMX5_CLK_I2C1_GATE], NULL, "imx21-i2c.0"); | 269 | clk_register_clkdev(clk[IMX5_CLK_I2C1_GATE], NULL, "imx21-i2c.0"); |
272 | clk_register_clkdev(clk[IMX5_CLK_I2C2_GATE], NULL, "imx21-i2c.1"); | 270 | clk_register_clkdev(clk[IMX5_CLK_I2C2_GATE], NULL, "imx21-i2c.1"); |
273 | clk_register_clkdev(clk[IMX5_CLK_USBOH3_PER_GATE], "per", "mxc-ehci.0"); | 271 | clk_register_clkdev(clk[IMX5_CLK_USBOH3_PER_GATE], "per", "mxc-ehci.0"); |
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 4d677f442539..b0e7f9d2c245 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c | |||
@@ -437,12 +437,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) | |||
437 | 437 | ||
438 | clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0"); | 438 | clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0"); |
439 | clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); | 439 | clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); |
440 | clk_register_clkdev(clk[cko1_sel], "cko1_sel", NULL); | 440 | clk_register_clkdev(clk[enet_ref], "enet_ref", NULL); |
441 | clk_register_clkdev(clk[ahb], "ahb", NULL); | ||
442 | clk_register_clkdev(clk[cko1], "cko1", NULL); | ||
443 | clk_register_clkdev(clk[arm], NULL, "cpu0"); | ||
444 | clk_register_clkdev(clk[pll4_post_div], "pll4_post_div", NULL); | ||
445 | clk_register_clkdev(clk[pll4_audio], "pll4_audio", NULL); | ||
446 | 441 | ||
447 | if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) || | 442 | if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) || |
448 | cpu_is_imx6dl()) { | 443 | cpu_is_imx6dl()) { |
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index 4c86f3035205..f7073c0782fb 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2013 Freescale Semiconductor, Inc. | 2 | * Copyright 2013-2014 Freescale Semiconductor, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
@@ -18,27 +18,43 @@ | |||
18 | #include "clk.h" | 18 | #include "clk.h" |
19 | #include "common.h" | 19 | #include "common.h" |
20 | 20 | ||
21 | static const char const *step_sels[] = { "osc", "pll2_pfd2", }; | 21 | #define CCSR 0xc |
22 | static const char const *pll1_sw_sels[] = { "pll1_sys", "step", }; | 22 | #define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2) |
23 | static const char const *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", }; | 23 | #define CACRR 0x10 |
24 | static const char const *ocram_sels[] = { "periph", "ocram_alt_sels", }; | 24 | #define CDHIPR 0x48 |
25 | static const char const *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", }; | 25 | #define BM_CDHIPR_ARM_PODF_BUSY (1 << 16) |
26 | static const char const *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", }; | 26 | #define ARM_WAIT_DIV_396M 2 |
27 | static const char const *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; | 27 | #define ARM_WAIT_DIV_792M 4 |
28 | static const char const *periph_sels[] = { "pre_periph_sel", "periph_clk2_podf", }; | 28 | #define ARM_WAIT_DIV_996M 6 |
29 | static const char const *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", }; | 29 | |
30 | static const char const *csi_lcdif_sels[] = { "mmdc", "pll2_pfd2", "pll3_120m", "pll3_pfd1", }; | 30 | #define PLL_ARM 0x0 |
31 | static const char const *usdhc_sels[] = { "pll2_pfd2", "pll2_pfd0", }; | 31 | #define BM_PLL_ARM_DIV_SELECT (0x7f << 0) |
32 | static const char const *ssi_sels[] = { "pll3_pfd2", "pll3_pfd3", "pll4_audio_div", "dummy", }; | 32 | #define BM_PLL_ARM_POWERDOWN (1 << 12) |
33 | static const char const *perclk_sels[] = { "ipg", "osc", }; | 33 | #define BM_PLL_ARM_ENABLE (1 << 13) |
34 | static const char const *epdc_pxp_sels[] = { "mmdc", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd1", }; | 34 | #define BM_PLL_ARM_LOCK (1 << 31) |
35 | static const char const *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", }; | 35 | #define PLL_ARM_DIV_792M 66 |
36 | static const char const *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", }; | 36 | |
37 | static const char const *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", }; | 37 | static const char *step_sels[] = { "osc", "pll2_pfd2", }; |
38 | static const char const *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", }; | 38 | static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; |
39 | static const char const *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", }; | 39 | static const char *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", }; |
40 | static const char const *ecspi_sels[] = { "pll3_60m", "osc", }; | 40 | static const char *ocram_sels[] = { "periph", "ocram_alt_sels", }; |
41 | static const char const *uart_sels[] = { "pll3_80m", "osc", }; | 41 | static const char *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", }; |
42 | static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", }; | ||
43 | static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; | ||
44 | static const char *periph_sels[] = { "pre_periph_sel", "periph_clk2_podf", }; | ||
45 | static const char *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", }; | ||
46 | static const char *csi_lcdif_sels[] = { "mmdc", "pll2_pfd2", "pll3_120m", "pll3_pfd1", }; | ||
47 | static const char *usdhc_sels[] = { "pll2_pfd2", "pll2_pfd0", }; | ||
48 | static const char *ssi_sels[] = { "pll3_pfd2", "pll3_pfd3", "pll4_audio_div", "dummy", }; | ||
49 | static const char *perclk_sels[] = { "ipg", "osc", }; | ||
50 | static const char *epdc_pxp_sels[] = { "mmdc", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd1", }; | ||
51 | static const char *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", }; | ||
52 | static const char *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", }; | ||
53 | static const char *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", }; | ||
54 | static const char *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", }; | ||
55 | static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", }; | ||
56 | static const char *ecspi_sels[] = { "pll3_60m", "osc", }; | ||
57 | static const char *uart_sels[] = { "pll3_80m", "osc", }; | ||
42 | 58 | ||
43 | static struct clk_div_table clk_enet_ref_table[] = { | 59 | static struct clk_div_table clk_enet_ref_table[] = { |
44 | { .val = 0, .div = 20, }, | 60 | { .val = 0, .div = 20, }, |
@@ -65,6 +81,89 @@ static struct clk_div_table video_div_table[] = { | |||
65 | 81 | ||
66 | static struct clk *clks[IMX6SL_CLK_END]; | 82 | static struct clk *clks[IMX6SL_CLK_END]; |
67 | static struct clk_onecell_data clk_data; | 83 | static struct clk_onecell_data clk_data; |
84 | static void __iomem *ccm_base; | ||
85 | static void __iomem *anatop_base; | ||
86 | |||
87 | static const u32 clks_init_on[] __initconst = { | ||
88 | IMX6SL_CLK_IPG, IMX6SL_CLK_ARM, IMX6SL_CLK_MMDC_ROOT, | ||
89 | }; | ||
90 | |||
91 | /* | ||
92 | * ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken | ||
93 | * during WAIT mode entry process could cause cache memory | ||
94 | * corruption. | ||
95 | * | ||
96 | * Software workaround: | ||
97 | * To prevent this issue from occurring, software should ensure that the | ||
98 | * ARM to IPG clock ratio is less than 12:5 (that is < 2.4x), before | ||
99 | * entering WAIT mode. | ||
100 | * | ||
101 | * This function will set the ARM clk to max value within the 12:5 limit. | ||
102 | * As IPG clock is fixed at 66MHz(so ARM freq must not exceed 158.4MHz), | ||
103 | * ARM freq are one of below setpoints: 396MHz, 792MHz and 996MHz, since | ||
104 | * the clk APIs can NOT be called in idle thread(may cause kernel schedule | ||
105 | * as there is sleep function in PLL wait function), so here we just slow | ||
106 | * down ARM to below freq according to previous freq: | ||
107 | * | ||
108 | * run mode wait mode | ||
109 | * 396MHz -> 132MHz; | ||
110 | * 792MHz -> 158.4MHz; | ||
111 | * 996MHz -> 142.3MHz; | ||
112 | */ | ||
113 | static int imx6sl_get_arm_divider_for_wait(void) | ||
114 | { | ||
115 | if (readl_relaxed(ccm_base + CCSR) & BM_CCSR_PLL1_SW_CLK_SEL) { | ||
116 | return ARM_WAIT_DIV_396M; | ||
117 | } else { | ||
118 | if ((readl_relaxed(anatop_base + PLL_ARM) & | ||
119 | BM_PLL_ARM_DIV_SELECT) == PLL_ARM_DIV_792M) | ||
120 | return ARM_WAIT_DIV_792M; | ||
121 | else | ||
122 | return ARM_WAIT_DIV_996M; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static void imx6sl_enable_pll_arm(bool enable) | ||
127 | { | ||
128 | static u32 saved_pll_arm; | ||
129 | u32 val; | ||
130 | |||
131 | if (enable) { | ||
132 | saved_pll_arm = val = readl_relaxed(anatop_base + PLL_ARM); | ||
133 | val |= BM_PLL_ARM_ENABLE; | ||
134 | val &= ~BM_PLL_ARM_POWERDOWN; | ||
135 | writel_relaxed(val, anatop_base + PLL_ARM); | ||
136 | while (!(__raw_readl(anatop_base + PLL_ARM) & BM_PLL_ARM_LOCK)) | ||
137 | ; | ||
138 | } else { | ||
139 | writel_relaxed(saved_pll_arm, anatop_base + PLL_ARM); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | void imx6sl_set_wait_clk(bool enter) | ||
144 | { | ||
145 | static unsigned long saved_arm_div; | ||
146 | int arm_div_for_wait = imx6sl_get_arm_divider_for_wait(); | ||
147 | |||
148 | /* | ||
149 | * According to hardware design, arm podf change need | ||
150 | * PLL1 clock enabled. | ||
151 | */ | ||
152 | if (arm_div_for_wait == ARM_WAIT_DIV_396M) | ||
153 | imx6sl_enable_pll_arm(true); | ||
154 | |||
155 | if (enter) { | ||
156 | saved_arm_div = readl_relaxed(ccm_base + CACRR); | ||
157 | writel_relaxed(arm_div_for_wait, ccm_base + CACRR); | ||
158 | } else { | ||
159 | writel_relaxed(saved_arm_div, ccm_base + CACRR); | ||
160 | } | ||
161 | while (__raw_readl(ccm_base + CDHIPR) & BM_CDHIPR_ARM_PODF_BUSY) | ||
162 | ; | ||
163 | |||
164 | if (arm_div_for_wait == ARM_WAIT_DIV_396M) | ||
165 | imx6sl_enable_pll_arm(false); | ||
166 | } | ||
68 | 167 | ||
69 | static void __init imx6sl_clocks_init(struct device_node *ccm_node) | 168 | static void __init imx6sl_clocks_init(struct device_node *ccm_node) |
70 | { | 169 | { |
@@ -72,6 +171,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) | |||
72 | void __iomem *base; | 171 | void __iomem *base; |
73 | int irq; | 172 | int irq; |
74 | int i; | 173 | int i; |
174 | int ret; | ||
75 | 175 | ||
76 | clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); | 176 | clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); |
77 | clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); | 177 | clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); |
@@ -80,6 +180,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) | |||
80 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); | 180 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); |
81 | base = of_iomap(np, 0); | 181 | base = of_iomap(np, 0); |
82 | WARN_ON(!base); | 182 | WARN_ON(!base); |
183 | anatop_base = base; | ||
83 | 184 | ||
84 | /* type name parent base div_mask */ | 185 | /* type name parent base div_mask */ |
85 | clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); | 186 | clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); |
@@ -127,6 +228,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) | |||
127 | np = ccm_node; | 228 | np = ccm_node; |
128 | base = of_iomap(np, 0); | 229 | base = of_iomap(np, 0); |
129 | WARN_ON(!base); | 230 | WARN_ON(!base); |
231 | ccm_base = base; | ||
130 | 232 | ||
131 | /* Reuse imx6q pm code */ | 233 | /* Reuse imx6q pm code */ |
132 | imx6q_pm_set_ccm_base(base); | 234 | imx6q_pm_set_ccm_base(base); |
@@ -258,6 +360,19 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) | |||
258 | clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); | 360 | clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); |
259 | clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); | 361 | clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); |
260 | 362 | ||
363 | /* Ensure the AHB clk is at 132MHz. */ | ||
364 | ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000); | ||
365 | if (ret) | ||
366 | pr_warn("%s: failed to set AHB clock rate %d!\n", | ||
367 | __func__, ret); | ||
368 | |||
369 | /* | ||
370 | * Make sure those always on clocks are enabled to maintain the correct | ||
371 | * usecount and enabling/disabling of parent PLLs. | ||
372 | */ | ||
373 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) | ||
374 | clk_prepare_enable(clks[clks_init_on[i]]); | ||
375 | |||
261 | if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { | 376 | if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { |
262 | clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]); | 377 | clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]); |
263 | clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); | 378 | clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); |
diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c index ecd66d8e20b6..22dc3ee21fd4 100644 --- a/arch/arm/mach-imx/clk-vf610.c +++ b/arch/arm/mach-imx/clk-vf610.c | |||
@@ -63,25 +63,25 @@ static void __iomem *anatop_base; | |||
63 | static void __iomem *ccm_base; | 63 | static void __iomem *ccm_base; |
64 | 64 | ||
65 | /* sources for multiplexer clocks, this is used multiple times */ | 65 | /* sources for multiplexer clocks, this is used multiple times */ |
66 | static const char const *fast_sels[] = { "firc", "fxosc", }; | 66 | static const char *fast_sels[] = { "firc", "fxosc", }; |
67 | static const char const *slow_sels[] = { "sirc_32k", "sxosc", }; | 67 | static const char *slow_sels[] = { "sirc_32k", "sxosc", }; |
68 | static const char const *pll1_sels[] = { "pll1_main", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", }; | 68 | static const char *pll1_sels[] = { "pll1_main", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", }; |
69 | static const char const *pll2_sels[] = { "pll2_main", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", }; | 69 | static const char *pll2_sels[] = { "pll2_main", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", }; |
70 | static const char const *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_main", "pll1_pfd_sel", "pll3_main", }; | 70 | static const char *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_main", "pll1_pfd_sel", "pll3_main", }; |
71 | static const char const *ddr_sels[] = { "pll2_pfd2", "sys_sel", }; | 71 | static const char *ddr_sels[] = { "pll2_pfd2", "sys_sel", }; |
72 | static const char const *rmii_sels[] = { "enet_ext", "audio_ext", "enet_50m", "enet_25m", }; | 72 | static const char *rmii_sels[] = { "enet_ext", "audio_ext", "enet_50m", "enet_25m", }; |
73 | static const char const *enet_ts_sels[] = { "enet_ext", "fxosc", "audio_ext", "usb", "enet_ts", "enet_25m", "enet_50m", }; | 73 | static const char *enet_ts_sels[] = { "enet_ext", "fxosc", "audio_ext", "usb", "enet_ts", "enet_25m", "enet_50m", }; |
74 | static const char const *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; | 74 | static const char *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; |
75 | static const char const *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; | 75 | static const char *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; |
76 | static const char const *nfc_sels[] = { "platform_bus", "pll1_pfd1", "pll3_pfd1", "pll3_pfd3", }; | 76 | static const char *nfc_sels[] = { "platform_bus", "pll1_pfd1", "pll3_pfd1", "pll3_pfd3", }; |
77 | static const char const *qspi_sels[] = { "pll3_main", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", }; | 77 | static const char *qspi_sels[] = { "pll3_main", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", }; |
78 | static const char const *esdhc_sels[] = { "pll3_main", "pll3_pfd3", "pll1_pfd3", "platform_bus", }; | 78 | static const char *esdhc_sels[] = { "pll3_main", "pll3_pfd3", "pll1_pfd3", "platform_bus", }; |
79 | static const char const *dcu_sels[] = { "pll1_pfd2", "pll3_main", }; | 79 | static const char *dcu_sels[] = { "pll1_pfd2", "pll3_main", }; |
80 | static const char const *gpu_sels[] = { "pll2_pfd2", "pll3_pfd2", }; | 80 | static const char *gpu_sels[] = { "pll2_pfd2", "pll3_pfd2", }; |
81 | static const char const *vadc_sels[] = { "pll6_main_div", "pll3_main_div", "pll3_main", }; | 81 | static const char *vadc_sels[] = { "pll6_main_div", "pll3_main_div", "pll3_main", }; |
82 | /* FTM counter clock source, not module clock */ | 82 | /* FTM counter clock source, not module clock */ |
83 | static const char const *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ext", }; | 83 | static const char *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ext", }; |
84 | static const char const *ftm_fix_sels[] = { "sxosc", "ipg_bus", }; | 84 | static const char *ftm_fix_sels[] = { "sxosc", "ipg_bus", }; |
85 | 85 | ||
86 | static struct clk_div_table pll4_main_div_table[] = { | 86 | static struct clk_div_table pll4_main_div_table[] = { |
87 | { .val = 0, .div = 1 }, | 87 | { .val = 0, .div = 1 }, |
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index baf439dc22d8..b5241ea76706 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. | 2 | * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
@@ -116,7 +116,6 @@ void imx_enable_cpu(int cpu, bool enable); | |||
116 | void imx_set_cpu_jump(int cpu, void *jump_addr); | 116 | void imx_set_cpu_jump(int cpu, void *jump_addr); |
117 | u32 imx_get_cpu_arg(int cpu); | 117 | u32 imx_get_cpu_arg(int cpu); |
118 | void imx_set_cpu_arg(int cpu, u32 arg); | 118 | void imx_set_cpu_arg(int cpu, u32 arg); |
119 | void v7_cpu_resume(void); | ||
120 | #ifdef CONFIG_SMP | 119 | #ifdef CONFIG_SMP |
121 | void v7_secondary_startup(void); | 120 | void v7_secondary_startup(void); |
122 | void imx_scu_map_io(void); | 121 | void imx_scu_map_io(void); |
@@ -139,13 +138,25 @@ void imx_anatop_init(void); | |||
139 | void imx_anatop_pre_suspend(void); | 138 | void imx_anatop_pre_suspend(void); |
140 | void imx_anatop_post_resume(void); | 139 | void imx_anatop_post_resume(void); |
141 | int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); | 140 | int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); |
142 | void imx6q_set_chicken_bit(void); | 141 | void imx6q_set_int_mem_clk_lpm(void); |
142 | void imx6sl_set_wait_clk(bool enter); | ||
143 | 143 | ||
144 | void imx_cpu_die(unsigned int cpu); | 144 | void imx_cpu_die(unsigned int cpu); |
145 | int imx_cpu_kill(unsigned int cpu); | 145 | int imx_cpu_kill(unsigned int cpu); |
146 | 146 | ||
147 | #ifdef CONFIG_SUSPEND | ||
148 | void v7_cpu_resume(void); | ||
149 | void imx6_suspend(void __iomem *ocram_vbase); | ||
150 | #else | ||
151 | static inline void v7_cpu_resume(void) {} | ||
152 | static inline void imx6_suspend(void __iomem *ocram_vbase) {} | ||
153 | #endif | ||
154 | |||
147 | void imx6q_pm_init(void); | 155 | void imx6q_pm_init(void); |
156 | void imx6dl_pm_init(void); | ||
157 | void imx6sl_pm_init(void); | ||
148 | void imx6q_pm_set_ccm_base(void __iomem *base); | 158 | void imx6q_pm_set_ccm_base(void __iomem *base); |
159 | |||
149 | #ifdef CONFIG_PM | 160 | #ifdef CONFIG_PM |
150 | void imx5_pm_init(void); | 161 | void imx5_pm_init(void); |
151 | #else | 162 | #else |
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index 23ddfb693b2d..6bcae0479049 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c | |||
@@ -68,8 +68,8 @@ int __init imx6q_cpuidle_init(void) | |||
68 | /* Need to enable SCU standby for entering WAIT modes */ | 68 | /* Need to enable SCU standby for entering WAIT modes */ |
69 | imx_scu_standby_enable(); | 69 | imx_scu_standby_enable(); |
70 | 70 | ||
71 | /* Set chicken bit to get a reliable WAIT mode support */ | 71 | /* Set INT_MEM_CLK_LPM bit to get a reliable WAIT mode support */ |
72 | imx6q_set_chicken_bit(); | 72 | imx6q_set_int_mem_clk_lpm(); |
73 | 73 | ||
74 | return cpuidle_register(&imx6q_cpuidle_driver, NULL); | 74 | return cpuidle_register(&imx6q_cpuidle_driver, NULL); |
75 | } | 75 | } |
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c new file mode 100644 index 000000000000..d4b6b8171fa9 --- /dev/null +++ b/arch/arm/mach-imx/cpuidle-imx6sl.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/cpuidle.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <asm/cpuidle.h> | ||
12 | #include <asm/proc-fns.h> | ||
13 | |||
14 | #include "common.h" | ||
15 | #include "cpuidle.h" | ||
16 | |||
17 | static int imx6sl_enter_wait(struct cpuidle_device *dev, | ||
18 | struct cpuidle_driver *drv, int index) | ||
19 | { | ||
20 | imx6q_set_lpm(WAIT_UNCLOCKED); | ||
21 | /* | ||
22 | * Software workaround for ERR005311, see function | ||
23 | * description for details. | ||
24 | */ | ||
25 | imx6sl_set_wait_clk(true); | ||
26 | cpu_do_idle(); | ||
27 | imx6sl_set_wait_clk(false); | ||
28 | imx6q_set_lpm(WAIT_CLOCKED); | ||
29 | |||
30 | return index; | ||
31 | } | ||
32 | |||
33 | static struct cpuidle_driver imx6sl_cpuidle_driver = { | ||
34 | .name = "imx6sl_cpuidle", | ||
35 | .owner = THIS_MODULE, | ||
36 | .states = { | ||
37 | /* WFI */ | ||
38 | ARM_CPUIDLE_WFI_STATE, | ||
39 | /* WAIT */ | ||
40 | { | ||
41 | .exit_latency = 50, | ||
42 | .target_residency = 75, | ||
43 | .flags = CPUIDLE_FLAG_TIME_VALID | | ||
44 | CPUIDLE_FLAG_TIMER_STOP, | ||
45 | .enter = imx6sl_enter_wait, | ||
46 | .name = "WAIT", | ||
47 | .desc = "Clock off", | ||
48 | }, | ||
49 | }, | ||
50 | .state_count = 2, | ||
51 | .safe_state_index = 0, | ||
52 | }; | ||
53 | |||
54 | int __init imx6sl_cpuidle_init(void) | ||
55 | { | ||
56 | return cpuidle_register(&imx6sl_cpuidle_driver, NULL); | ||
57 | } | ||
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h index 786f98ecc145..24e33670417c 100644 --- a/arch/arm/mach-imx/cpuidle.h +++ b/arch/arm/mach-imx/cpuidle.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #ifdef CONFIG_CPU_IDLE | 13 | #ifdef CONFIG_CPU_IDLE |
14 | extern int imx5_cpuidle_init(void); | 14 | extern int imx5_cpuidle_init(void); |
15 | extern int imx6q_cpuidle_init(void); | 15 | extern int imx6q_cpuidle_init(void); |
16 | extern int imx6sl_cpuidle_init(void); | ||
16 | #else | 17 | #else |
17 | static inline int imx5_cpuidle_init(void) | 18 | static inline int imx5_cpuidle_init(void) |
18 | { | 19 | { |
@@ -22,4 +23,8 @@ static inline int imx6q_cpuidle_init(void) | |||
22 | { | 23 | { |
23 | return 0; | 24 | return 0; |
24 | } | 25 | } |
26 | static inline int imx6sl_cpuidle_init(void) | ||
27 | { | ||
28 | return 0; | ||
29 | } | ||
25 | #endif | 30 | #endif |
diff --git a/arch/arm/mach-imx/devices-imx25.h b/arch/arm/mach-imx/devices-imx25.h index 769563fdeaa0..61a114cddc39 100644 --- a/arch/arm/mach-imx/devices-imx25.h +++ b/arch/arm/mach-imx/devices-imx25.h | |||
@@ -83,7 +83,3 @@ extern const struct imx_spi_imx_data imx25_cspi_data[]; | |||
83 | #define imx25_add_spi_imx0(pdata) imx25_add_spi_imx(0, pdata) | 83 | #define imx25_add_spi_imx0(pdata) imx25_add_spi_imx(0, pdata) |
84 | #define imx25_add_spi_imx1(pdata) imx25_add_spi_imx(1, pdata) | 84 | #define imx25_add_spi_imx1(pdata) imx25_add_spi_imx(1, pdata) |
85 | #define imx25_add_spi_imx2(pdata) imx25_add_spi_imx(2, pdata) | 85 | #define imx25_add_spi_imx2(pdata) imx25_add_spi_imx(2, pdata) |
86 | |||
87 | extern struct imx_mxc_pwm_data imx25_mxc_pwm_data[]; | ||
88 | #define imx25_add_mxc_pwm(id) \ | ||
89 | imx_add_mxc_pwm(&imx25_mxc_pwm_data[id]) | ||
diff --git a/arch/arm/mach-imx/devices-imx51.h b/arch/arm/mach-imx/devices-imx51.h index deee5baee88c..26389f35a2b2 100644 --- a/arch/arm/mach-imx/devices-imx51.h +++ b/arch/arm/mach-imx/devices-imx51.h | |||
@@ -57,10 +57,6 @@ extern const struct imx_imx2_wdt_data imx51_imx2_wdt_data[]; | |||
57 | #define imx51_add_imx2_wdt(id) \ | 57 | #define imx51_add_imx2_wdt(id) \ |
58 | imx_add_imx2_wdt(&imx51_imx2_wdt_data[id]) | 58 | imx_add_imx2_wdt(&imx51_imx2_wdt_data[id]) |
59 | 59 | ||
60 | extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[]; | ||
61 | #define imx51_add_mxc_pwm(id) \ | ||
62 | imx_add_mxc_pwm(&imx51_mxc_pwm_data[id]) | ||
63 | |||
64 | extern const struct imx_imx_keypad_data imx51_imx_keypad_data; | 60 | extern const struct imx_imx_keypad_data imx51_imx_keypad_data; |
65 | #define imx51_add_imx_keypad(pdata) \ | 61 | #define imx51_add_imx_keypad(pdata) \ |
66 | imx_add_imx_keypad(&imx51_imx_keypad_data, pdata) | 62 | imx_add_imx_keypad(&imx51_imx_keypad_data, pdata) |
diff --git a/arch/arm/mach-imx/devices/Kconfig b/arch/arm/mach-imx/devices/Kconfig index 68c74fb0373c..2d260a5a307c 100644 --- a/arch/arm/mach-imx/devices/Kconfig +++ b/arch/arm/mach-imx/devices/Kconfig | |||
@@ -67,9 +67,6 @@ config IMX_HAVE_PLATFORM_MXC_MMC | |||
67 | config IMX_HAVE_PLATFORM_MXC_NAND | 67 | config IMX_HAVE_PLATFORM_MXC_NAND |
68 | bool | 68 | bool |
69 | 69 | ||
70 | config IMX_HAVE_PLATFORM_MXC_PWM | ||
71 | bool | ||
72 | |||
73 | config IMX_HAVE_PLATFORM_MXC_RNGA | 70 | config IMX_HAVE_PLATFORM_MXC_RNGA |
74 | bool | 71 | bool |
75 | select ARCH_HAS_RNGA | 72 | select ARCH_HAS_RNGA |
diff --git a/arch/arm/mach-imx/devices/Makefile b/arch/arm/mach-imx/devices/Makefile index 67416fb1dc69..1cbc14cd80d1 100644 --- a/arch/arm/mach-imx/devices/Makefile +++ b/arch/arm/mach-imx/devices/Makefile | |||
@@ -23,7 +23,6 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_CAMERA) += platform-mx2-camera.o | |||
23 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI) += platform-mxc-ehci.o | 23 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI) += platform-mxc-ehci.o |
24 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_MMC) += platform-mxc-mmc.o | 24 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_MMC) += platform-mxc-mmc.o |
25 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o | 25 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o |
26 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_PWM) += platform-mxc_pwm.o | ||
27 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RNGA) += platform-mxc_rnga.o | 26 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RNGA) += platform-mxc_rnga.o |
28 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RTC) += platform-mxc_rtc.o | 27 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RTC) += platform-mxc_rtc.o |
29 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o | 28 | obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o |
diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h index c13b76b9f6b3..61352a80bb59 100644 --- a/arch/arm/mach-imx/devices/devices-common.h +++ b/arch/arm/mach-imx/devices/devices-common.h | |||
@@ -290,15 +290,6 @@ struct imx_pata_imx_data { | |||
290 | struct platform_device *__init imx_add_pata_imx( | 290 | struct platform_device *__init imx_add_pata_imx( |
291 | const struct imx_pata_imx_data *data); | 291 | const struct imx_pata_imx_data *data); |
292 | 292 | ||
293 | struct imx_mxc_pwm_data { | ||
294 | int id; | ||
295 | resource_size_t iobase; | ||
296 | resource_size_t iosize; | ||
297 | resource_size_t irq; | ||
298 | }; | ||
299 | struct platform_device *__init imx_add_mxc_pwm( | ||
300 | const struct imx_mxc_pwm_data *data); | ||
301 | |||
302 | /* mxc_rtc */ | 293 | /* mxc_rtc */ |
303 | struct imx_mxc_rtc_data { | 294 | struct imx_mxc_rtc_data { |
304 | const char *devid; | 295 | const char *devid; |
diff --git a/arch/arm/mach-imx/devices/platform-mxc_pwm.c b/arch/arm/mach-imx/devices/platform-mxc_pwm.c deleted file mode 100644 index dcd289777687..000000000000 --- a/arch/arm/mach-imx/devices/platform-mxc_pwm.c +++ /dev/null | |||
@@ -1,69 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010 Pengutronix | ||
3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it under | ||
6 | * the terms of the GNU General Public License version 2 as published by the | ||
7 | * Free Software Foundation. | ||
8 | */ | ||
9 | #include "../hardware.h" | ||
10 | #include "devices-common.h" | ||
11 | |||
12 | #define imx_mxc_pwm_data_entry_single(soc, _id, _hwid, _size) \ | ||
13 | { \ | ||
14 | .id = _id, \ | ||
15 | .iobase = soc ## _PWM ## _hwid ## _BASE_ADDR, \ | ||
16 | .iosize = _size, \ | ||
17 | .irq = soc ## _INT_PWM ## _hwid, \ | ||
18 | } | ||
19 | #define imx_mxc_pwm_data_entry(soc, _id, _hwid, _size) \ | ||
20 | [_id] = imx_mxc_pwm_data_entry_single(soc, _id, _hwid, _size) | ||
21 | |||
22 | #ifdef CONFIG_SOC_IMX21 | ||
23 | const struct imx_mxc_pwm_data imx21_mxc_pwm_data __initconst = | ||
24 | imx_mxc_pwm_data_entry_single(MX21, 0, , SZ_4K); | ||
25 | #endif /* ifdef CONFIG_SOC_IMX21 */ | ||
26 | |||
27 | #ifdef CONFIG_SOC_IMX25 | ||
28 | const struct imx_mxc_pwm_data imx25_mxc_pwm_data[] __initconst = { | ||
29 | #define imx25_mxc_pwm_data_entry(_id, _hwid) \ | ||
30 | imx_mxc_pwm_data_entry(MX25, _id, _hwid, SZ_16K) | ||
31 | imx25_mxc_pwm_data_entry(0, 1), | ||
32 | imx25_mxc_pwm_data_entry(1, 2), | ||
33 | imx25_mxc_pwm_data_entry(2, 3), | ||
34 | imx25_mxc_pwm_data_entry(3, 4), | ||
35 | }; | ||
36 | #endif /* ifdef CONFIG_SOC_IMX25 */ | ||
37 | |||
38 | #ifdef CONFIG_SOC_IMX27 | ||
39 | const struct imx_mxc_pwm_data imx27_mxc_pwm_data __initconst = | ||
40 | imx_mxc_pwm_data_entry_single(MX27, 0, , SZ_4K); | ||
41 | #endif /* ifdef CONFIG_SOC_IMX27 */ | ||
42 | |||
43 | #ifdef CONFIG_SOC_IMX51 | ||
44 | const struct imx_mxc_pwm_data imx51_mxc_pwm_data[] __initconst = { | ||
45 | #define imx51_mxc_pwm_data_entry(_id, _hwid) \ | ||
46 | imx_mxc_pwm_data_entry(MX51, _id, _hwid, SZ_16K) | ||
47 | imx51_mxc_pwm_data_entry(0, 1), | ||
48 | imx51_mxc_pwm_data_entry(1, 2), | ||
49 | }; | ||
50 | #endif /* ifdef CONFIG_SOC_IMX51 */ | ||
51 | |||
52 | struct platform_device *__init imx_add_mxc_pwm( | ||
53 | const struct imx_mxc_pwm_data *data) | ||
54 | { | ||
55 | struct resource res[] = { | ||
56 | { | ||
57 | .start = data->iobase, | ||
58 | .end = data->iobase + data->iosize - 1, | ||
59 | .flags = IORESOURCE_MEM, | ||
60 | }, { | ||
61 | .start = data->irq, | ||
62 | .end = data->irq, | ||
63 | .flags = IORESOURCE_IRQ, | ||
64 | }, | ||
65 | }; | ||
66 | |||
67 | return imx_add_platform_device("mxc_pwm", data->id, | ||
68 | res, ARRAY_SIZE(res), NULL, 0); | ||
69 | } | ||
diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h index a3b0b04b45c9..abf43bb47eca 100644 --- a/arch/arm/mach-imx/hardware.h +++ b/arch/arm/mach-imx/hardware.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. | 2 | * Copyright 2004-2007, 2014 Freescale Semiconductor, Inc. All Rights Reserved. |
3 | * Copyright 2008 Juergen Beisert, kernel@pengutronix.de | 3 | * Copyright 2008 Juergen Beisert, kernel@pengutronix.de |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
@@ -20,7 +20,9 @@ | |||
20 | #ifndef __ASM_ARCH_MXC_HARDWARE_H__ | 20 | #ifndef __ASM_ARCH_MXC_HARDWARE_H__ |
21 | #define __ASM_ARCH_MXC_HARDWARE_H__ | 21 | #define __ASM_ARCH_MXC_HARDWARE_H__ |
22 | 22 | ||
23 | #ifndef __ASSEMBLY__ | ||
23 | #include <asm/io.h> | 24 | #include <asm/io.h> |
25 | #endif | ||
24 | #include <asm/sizes.h> | 26 | #include <asm/sizes.h> |
25 | 27 | ||
26 | #define addr_in_module(addr, mod) \ | 28 | #define addr_in_module(addr, mod) \ |
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 627f16f0e9d1..de5047c8a6c8 100644 --- a/arch/arm/mach-imx/headsmp.S +++ b/arch/arm/mach-imx/headsmp.S | |||
@@ -12,12 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <asm/asm-offsets.h> | ||
16 | #include <asm/hardware/cache-l2x0.h> | ||
17 | 15 | ||
18 | .section ".text.head", "ax" | ||
19 | |||
20 | #ifdef CONFIG_SMP | ||
21 | diag_reg_offset: | 16 | diag_reg_offset: |
22 | .word g_diag_reg - . | 17 | .word g_diag_reg - . |
23 | 18 | ||
@@ -34,38 +29,3 @@ ENTRY(v7_secondary_startup) | |||
34 | set_diag_reg | 29 | set_diag_reg |
35 | b secondary_startup | 30 | b secondary_startup |
36 | ENDPROC(v7_secondary_startup) | 31 | ENDPROC(v7_secondary_startup) |
37 | #endif | ||
38 | |||
39 | #ifdef CONFIG_ARM_CPU_SUSPEND | ||
40 | /* | ||
41 | * The following code must assume it is running from physical address | ||
42 | * where absolute virtual addresses to the data section have to be | ||
43 | * turned into relative ones. | ||
44 | */ | ||
45 | |||
46 | #ifdef CONFIG_CACHE_L2X0 | ||
47 | .macro pl310_resume | ||
48 | adr r0, l2x0_saved_regs_offset | ||
49 | ldr r2, [r0] | ||
50 | add r2, r2, r0 | ||
51 | ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0 | ||
52 | ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value | ||
53 | str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl | ||
54 | mov r1, #0x1 | ||
55 | str r1, [r0, #L2X0_CTRL] @ re-enable L2 | ||
56 | .endm | ||
57 | |||
58 | l2x0_saved_regs_offset: | ||
59 | .word l2x0_saved_regs - . | ||
60 | |||
61 | #else | ||
62 | .macro pl310_resume | ||
63 | .endm | ||
64 | #endif | ||
65 | |||
66 | ENTRY(v7_cpu_resume) | ||
67 | bl v7_invalidate_l1 | ||
68 | pl310_resume | ||
69 | b cpu_resume | ||
70 | ENDPROC(v7_cpu_resume) | ||
71 | #endif | ||
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 76e5db4fce35..e60456d85c9d 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c | |||
@@ -182,16 +182,83 @@ static void __init imx6q_enet_phy_init(void) | |||
182 | 182 | ||
183 | static void __init imx6q_1588_init(void) | 183 | static void __init imx6q_1588_init(void) |
184 | { | 184 | { |
185 | struct device_node *np; | ||
186 | struct clk *ptp_clk; | ||
187 | struct clk *enet_ref; | ||
185 | struct regmap *gpr; | 188 | struct regmap *gpr; |
189 | u32 clksel; | ||
186 | 190 | ||
191 | np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec"); | ||
192 | if (!np) { | ||
193 | pr_warn("%s: failed to find fec node\n", __func__); | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | ptp_clk = of_clk_get(np, 2); | ||
198 | if (IS_ERR(ptp_clk)) { | ||
199 | pr_warn("%s: failed to get ptp clock\n", __func__); | ||
200 | goto put_node; | ||
201 | } | ||
202 | |||
203 | enet_ref = clk_get_sys(NULL, "enet_ref"); | ||
204 | if (IS_ERR(enet_ref)) { | ||
205 | pr_warn("%s: failed to get enet clock\n", __func__); | ||
206 | goto put_ptp_clk; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * If enet_ref from ANATOP/CCM is the PTP clock source, we need to | ||
211 | * set bit IOMUXC_GPR1[21]. Or the PTP clock must be from pad | ||
212 | * (external OSC), and we need to clear the bit. | ||
213 | */ | ||
214 | clksel = ptp_clk == enet_ref ? IMX6Q_GPR1_ENET_CLK_SEL_ANATOP : | ||
215 | IMX6Q_GPR1_ENET_CLK_SEL_PAD; | ||
187 | gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); | 216 | gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); |
188 | if (!IS_ERR(gpr)) | 217 | if (!IS_ERR(gpr)) |
189 | regmap_update_bits(gpr, IOMUXC_GPR1, | 218 | regmap_update_bits(gpr, IOMUXC_GPR1, |
190 | IMX6Q_GPR1_ENET_CLK_SEL_MASK, | 219 | IMX6Q_GPR1_ENET_CLK_SEL_MASK, |
191 | IMX6Q_GPR1_ENET_CLK_SEL_ANATOP); | 220 | clksel); |
192 | else | 221 | else |
193 | pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); | 222 | pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); |
194 | 223 | ||
224 | clk_put(enet_ref); | ||
225 | put_ptp_clk: | ||
226 | clk_put(ptp_clk); | ||
227 | put_node: | ||
228 | of_node_put(np); | ||
229 | } | ||
230 | |||
231 | static void __init imx6q_axi_init(void) | ||
232 | { | ||
233 | struct regmap *gpr; | ||
234 | unsigned int mask; | ||
235 | |||
236 | gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); | ||
237 | if (!IS_ERR(gpr)) { | ||
238 | /* | ||
239 | * Enable the cacheable attribute of VPU and IPU | ||
240 | * AXI transactions. | ||
241 | */ | ||
242 | mask = IMX6Q_GPR4_VPU_WR_CACHE_SEL | | ||
243 | IMX6Q_GPR4_VPU_RD_CACHE_SEL | | ||
244 | IMX6Q_GPR4_VPU_P_WR_CACHE_VAL | | ||
245 | IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK | | ||
246 | IMX6Q_GPR4_IPU_WR_CACHE_CTL | | ||
247 | IMX6Q_GPR4_IPU_RD_CACHE_CTL; | ||
248 | regmap_update_bits(gpr, IOMUXC_GPR4, mask, mask); | ||
249 | |||
250 | /* Increase IPU read QoS priority */ | ||
251 | regmap_update_bits(gpr, IOMUXC_GPR6, | ||
252 | IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK | | ||
253 | IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK, | ||
254 | (0xf << 16) | (0x7 << 20)); | ||
255 | regmap_update_bits(gpr, IOMUXC_GPR7, | ||
256 | IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK | | ||
257 | IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK, | ||
258 | (0xf << 16) | (0x7 << 20)); | ||
259 | } else { | ||
260 | pr_warn("failed to find fsl,imx6q-iomuxc-gpr regmap\n"); | ||
261 | } | ||
195 | } | 262 | } |
196 | 263 | ||
197 | static void __init imx6q_init_machine(void) | 264 | static void __init imx6q_init_machine(void) |
@@ -212,15 +279,18 @@ static void __init imx6q_init_machine(void) | |||
212 | of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); | 279 | of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); |
213 | 280 | ||
214 | imx_anatop_init(); | 281 | imx_anatop_init(); |
215 | imx6q_pm_init(); | 282 | cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); |
216 | imx6q_1588_init(); | 283 | imx6q_1588_init(); |
284 | imx6q_axi_init(); | ||
217 | } | 285 | } |
218 | 286 | ||
219 | #define OCOTP_CFG3 0x440 | 287 | #define OCOTP_CFG3 0x440 |
220 | #define OCOTP_CFG3_SPEED_SHIFT 16 | 288 | #define OCOTP_CFG3_SPEED_SHIFT 16 |
221 | #define OCOTP_CFG3_SPEED_1P2GHZ 0x3 | 289 | #define OCOTP_CFG3_SPEED_1P2GHZ 0x3 |
290 | #define OCOTP_CFG3_SPEED_996MHZ 0x2 | ||
291 | #define OCOTP_CFG3_SPEED_852MHZ 0x1 | ||
222 | 292 | ||
223 | static void __init imx6q_opp_check_1p2ghz(struct device *cpu_dev) | 293 | static void __init imx6q_opp_check_speed_grading(struct device *cpu_dev) |
224 | { | 294 | { |
225 | struct device_node *np; | 295 | struct device_node *np; |
226 | void __iomem *base; | 296 | void __iomem *base; |
@@ -238,11 +308,29 @@ static void __init imx6q_opp_check_1p2ghz(struct device *cpu_dev) | |||
238 | goto put_node; | 308 | goto put_node; |
239 | } | 309 | } |
240 | 310 | ||
311 | /* | ||
312 | * SPEED_GRADING[1:0] defines the max speed of ARM: | ||
313 | * 2b'11: 1200000000Hz; | ||
314 | * 2b'10: 996000000Hz; | ||
315 | * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. | ||
316 | * 2b'00: 792000000Hz; | ||
317 | * We need to set the max speed of ARM according to fuse map. | ||
318 | */ | ||
241 | val = readl_relaxed(base + OCOTP_CFG3); | 319 | val = readl_relaxed(base + OCOTP_CFG3); |
242 | val >>= OCOTP_CFG3_SPEED_SHIFT; | 320 | val >>= OCOTP_CFG3_SPEED_SHIFT; |
243 | if ((val & 0x3) != OCOTP_CFG3_SPEED_1P2GHZ) | 321 | val &= 0x3; |
322 | |||
323 | if (val != OCOTP_CFG3_SPEED_1P2GHZ) | ||
244 | if (dev_pm_opp_disable(cpu_dev, 1200000000)) | 324 | if (dev_pm_opp_disable(cpu_dev, 1200000000)) |
245 | pr_warn("failed to disable 1.2 GHz OPP\n"); | 325 | pr_warn("failed to disable 1.2 GHz OPP\n"); |
326 | if (val < OCOTP_CFG3_SPEED_996MHZ) | ||
327 | if (dev_pm_opp_disable(cpu_dev, 996000000)) | ||
328 | pr_warn("failed to disable 996 MHz OPP\n"); | ||
329 | if (cpu_is_imx6q()) { | ||
330 | if (val != OCOTP_CFG3_SPEED_852MHZ) | ||
331 | if (dev_pm_opp_disable(cpu_dev, 852000000)) | ||
332 | pr_warn("failed to disable 852 MHz OPP\n"); | ||
333 | } | ||
246 | 334 | ||
247 | put_node: | 335 | put_node: |
248 | of_node_put(np); | 336 | of_node_put(np); |
@@ -268,7 +356,7 @@ static void __init imx6q_opp_init(void) | |||
268 | goto put_node; | 356 | goto put_node; |
269 | } | 357 | } |
270 | 358 | ||
271 | imx6q_opp_check_1p2ghz(cpu_dev); | 359 | imx6q_opp_check_speed_grading(cpu_dev); |
272 | 360 | ||
273 | put_node: | 361 | put_node: |
274 | of_node_put(np); | 362 | of_node_put(np); |
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index 0f4fd4c0ab8e..ad323385115c 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/mach/map.h> | 17 | #include <asm/mach/map.h> |
18 | 18 | ||
19 | #include "common.h" | 19 | #include "common.h" |
20 | #include "cpuidle.h" | ||
20 | 21 | ||
21 | static void __init imx6sl_fec_init(void) | 22 | static void __init imx6sl_fec_init(void) |
22 | { | 23 | { |
@@ -39,6 +40,8 @@ static void __init imx6sl_init_late(void) | |||
39 | /* imx6sl reuses imx6q cpufreq driver */ | 40 | /* imx6sl reuses imx6q cpufreq driver */ |
40 | if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) | 41 | if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) |
41 | platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); | 42 | platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); |
43 | |||
44 | imx6sl_cpuidle_init(); | ||
42 | } | 45 | } |
43 | 46 | ||
44 | static void __init imx6sl_init_machine(void) | 47 | static void __init imx6sl_init_machine(void) |
@@ -55,8 +58,7 @@ static void __init imx6sl_init_machine(void) | |||
55 | 58 | ||
56 | imx6sl_fec_init(); | 59 | imx6sl_fec_init(); |
57 | imx_anatop_init(); | 60 | imx_anatop_init(); |
58 | /* Reuse imx6q pm code */ | 61 | imx6sl_pm_init(); |
59 | imx6q_pm_init(); | ||
60 | } | 62 | } |
61 | 63 | ||
62 | static void __init imx6sl_init_irq(void) | 64 | static void __init imx6sl_init_irq(void) |
diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c index 9821b824dcaf..a7a4a9c67615 100644 --- a/arch/arm/mach-imx/mach-mx27ads.c +++ b/arch/arm/mach-imx/mach-mx27ads.c | |||
@@ -21,6 +21,10 @@ | |||
21 | #include <linux/mtd/physmap.h> | 21 | #include <linux/mtd/physmap.h> |
22 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
23 | #include <linux/irq.h> | 23 | #include <linux/irq.h> |
24 | |||
25 | #include <linux/regulator/fixed.h> | ||
26 | #include <linux/regulator/machine.h> | ||
27 | |||
24 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
25 | #include <asm/mach/arch.h> | 29 | #include <asm/mach/arch.h> |
26 | #include <asm/mach/time.h> | 30 | #include <asm/mach/time.h> |
@@ -195,14 +199,58 @@ static const struct imxi2c_platform_data mx27ads_i2c1_data __initconst = { | |||
195 | static struct i2c_board_info mx27ads_i2c_devices[] = { | 199 | static struct i2c_board_info mx27ads_i2c_devices[] = { |
196 | }; | 200 | }; |
197 | 201 | ||
198 | void lcd_power(int on) | 202 | static void vgpio_set(struct gpio_chip *chip, unsigned offset, int value) |
199 | { | 203 | { |
200 | if (on) | 204 | if (value) |
201 | __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_SET_REG); | 205 | __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_SET_REG); |
202 | else | 206 | else |
203 | __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_CLEAR_REG); | 207 | __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_CLEAR_REG); |
204 | } | 208 | } |
205 | 209 | ||
210 | static int vgpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) | ||
211 | { | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | #define MX27ADS_LCD_GPIO (6 * 32) | ||
216 | |||
217 | static struct regulator_consumer_supply mx27ads_lcd_regulator_consumer = | ||
218 | REGULATOR_SUPPLY("lcd", "imx-fb.0"); | ||
219 | |||
220 | static struct regulator_init_data mx27ads_lcd_regulator_init_data = { | ||
221 | .constraints = { | ||
222 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
223 | }, | ||
224 | .consumer_supplies = &mx27ads_lcd_regulator_consumer, | ||
225 | .num_consumer_supplies = 1, | ||
226 | }; | ||
227 | |||
228 | static struct fixed_voltage_config mx27ads_lcd_regulator_pdata = { | ||
229 | .supply_name = "LCD", | ||
230 | .microvolts = 3300000, | ||
231 | .gpio = MX27ADS_LCD_GPIO, | ||
232 | .init_data = &mx27ads_lcd_regulator_init_data, | ||
233 | }; | ||
234 | |||
235 | static void __init mx27ads_regulator_init(void) | ||
236 | { | ||
237 | struct gpio_chip *vchip; | ||
238 | |||
239 | vchip = kzalloc(sizeof(*vchip), GFP_KERNEL); | ||
240 | vchip->owner = THIS_MODULE; | ||
241 | vchip->label = "LCD"; | ||
242 | vchip->base = MX27ADS_LCD_GPIO; | ||
243 | vchip->ngpio = 1; | ||
244 | vchip->direction_output = vgpio_dir_out; | ||
245 | vchip->set = vgpio_set; | ||
246 | gpiochip_add(vchip); | ||
247 | |||
248 | platform_device_register_data(&platform_bus, "reg-fixed-voltage", | ||
249 | PLATFORM_DEVID_AUTO, | ||
250 | &mx27ads_lcd_regulator_pdata, | ||
251 | sizeof(mx27ads_lcd_regulator_pdata)); | ||
252 | } | ||
253 | |||
206 | static struct imx_fb_videomode mx27ads_modes[] = { | 254 | static struct imx_fb_videomode mx27ads_modes[] = { |
207 | { | 255 | { |
208 | .mode = { | 256 | .mode = { |
@@ -239,8 +287,6 @@ static const struct imx_fb_platform_data mx27ads_fb_data __initconst = { | |||
239 | .pwmr = 0x00A903FF, | 287 | .pwmr = 0x00A903FF, |
240 | .lscr1 = 0x00120300, | 288 | .lscr1 = 0x00120300, |
241 | .dmacr = 0x00020010, | 289 | .dmacr = 0x00020010, |
242 | |||
243 | .lcd_power = lcd_power, | ||
244 | }; | 290 | }; |
245 | 291 | ||
246 | static int mx27ads_sdhc1_init(struct device *dev, irq_handler_t detect_irq, | 292 | static int mx27ads_sdhc1_init(struct device *dev, irq_handler_t detect_irq, |
@@ -304,6 +350,7 @@ static void __init mx27ads_board_init(void) | |||
304 | i2c_register_board_info(1, mx27ads_i2c_devices, | 350 | i2c_register_board_info(1, mx27ads_i2c_devices, |
305 | ARRAY_SIZE(mx27ads_i2c_devices)); | 351 | ARRAY_SIZE(mx27ads_i2c_devices)); |
306 | imx27_add_imx_i2c(1, &mx27ads_i2c1_data); | 352 | imx27_add_imx_i2c(1, &mx27ads_i2c1_data); |
353 | mx27ads_regulator_init(); | ||
307 | imx27_add_imx_fb(&mx27ads_fb_data); | 354 | imx27_add_imx_fb(&mx27ads_fb_data); |
308 | imx27_add_mxc_mmc(0, &sdhc1_pdata); | 355 | imx27_add_mxc_mmc(0, &sdhc1_pdata); |
309 | imx27_add_mxc_mmc(1, &sdhc2_pdata); | 356 | imx27_add_mxc_mmc(1, &sdhc2_pdata); |
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index b3738e616f19..8f45afe785f8 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c | |||
@@ -128,27 +128,15 @@ static struct platform_device mx31moboard_flash = { | |||
128 | .num_resources = 1, | 128 | .num_resources = 1, |
129 | }; | 129 | }; |
130 | 130 | ||
131 | static int moboard_uart0_init(struct platform_device *pdev) | 131 | static void __init moboard_uart0_init(void) |
132 | { | 132 | { |
133 | int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack"); | 133 | if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack")) { |
134 | if (ret) | 134 | gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0); |
135 | return ret; | ||
136 | |||
137 | ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0); | ||
138 | if (ret) | ||
139 | gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); | 135 | gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); |
140 | 136 | } | |
141 | return ret; | ||
142 | } | ||
143 | |||
144 | static void moboard_uart0_exit(struct platform_device *pdev) | ||
145 | { | ||
146 | gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); | ||
147 | } | 137 | } |
148 | 138 | ||
149 | static const struct imxuart_platform_data uart0_pdata __initconst = { | 139 | static const struct imxuart_platform_data uart0_pdata __initconst = { |
150 | .init = moboard_uart0_init, | ||
151 | .exit = moboard_uart0_exit, | ||
152 | }; | 140 | }; |
153 | 141 | ||
154 | static const struct imxuart_platform_data uart4_pdata __initconst = { | 142 | static const struct imxuart_platform_data uart4_pdata __initconst = { |
@@ -543,6 +531,7 @@ static void __init mx31moboard_init(void) | |||
543 | 531 | ||
544 | imx31_add_imx2_wdt(); | 532 | imx31_add_imx2_wdt(); |
545 | 533 | ||
534 | moboard_uart0_init(); | ||
546 | imx31_add_imx_uart0(&uart0_pdata); | 535 | imx31_add_imx_uart0(&uart0_pdata); |
547 | imx31_add_imx_uart4(&uart4_pdata); | 536 | imx31_add_imx_uart4(&uart4_pdata); |
548 | 537 | ||
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c new file mode 100644 index 000000000000..9392a8f4ef24 --- /dev/null +++ b/arch/arm/mach-imx/pm-imx6.c | |||
@@ -0,0 +1,551 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2014 Freescale Semiconductor, Inc. | ||
3 | * Copyright 2011 Linaro Ltd. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/genalloc.h> | ||
18 | #include <linux/mfd/syscon.h> | ||
19 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/of_address.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/suspend.h> | ||
25 | #include <asm/cacheflush.h> | ||
26 | #include <asm/fncpy.h> | ||
27 | #include <asm/proc-fns.h> | ||
28 | #include <asm/suspend.h> | ||
29 | #include <asm/tlb.h> | ||
30 | |||
31 | #include "common.h" | ||
32 | #include "hardware.h" | ||
33 | |||
34 | #define CCR 0x0 | ||
35 | #define BM_CCR_WB_COUNT (0x7 << 16) | ||
36 | #define BM_CCR_RBC_BYPASS_COUNT (0x3f << 21) | ||
37 | #define BM_CCR_RBC_EN (0x1 << 27) | ||
38 | |||
39 | #define CLPCR 0x54 | ||
40 | #define BP_CLPCR_LPM 0 | ||
41 | #define BM_CLPCR_LPM (0x3 << 0) | ||
42 | #define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) | ||
43 | #define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) | ||
44 | #define BM_CLPCR_SBYOS (0x1 << 6) | ||
45 | #define BM_CLPCR_DIS_REF_OSC (0x1 << 7) | ||
46 | #define BM_CLPCR_VSTBY (0x1 << 8) | ||
47 | #define BP_CLPCR_STBY_COUNT 9 | ||
48 | #define BM_CLPCR_STBY_COUNT (0x3 << 9) | ||
49 | #define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) | ||
50 | #define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) | ||
51 | #define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) | ||
52 | #define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) | ||
53 | #define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) | ||
54 | #define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) | ||
55 | #define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) | ||
56 | #define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) | ||
57 | #define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) | ||
58 | #define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) | ||
59 | #define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) | ||
60 | |||
61 | #define CGPR 0x64 | ||
62 | #define BM_CGPR_INT_MEM_CLK_LPM (0x1 << 17) | ||
63 | |||
64 | #define MX6Q_SUSPEND_OCRAM_SIZE 0x1000 | ||
65 | #define MX6_MAX_MMDC_IO_NUM 33 | ||
66 | |||
67 | static void __iomem *ccm_base; | ||
68 | static void __iomem *suspend_ocram_base; | ||
69 | static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase); | ||
70 | |||
71 | /* | ||
72 | * suspend ocram space layout: | ||
73 | * ======================== high address ====================== | ||
74 | * . | ||
75 | * . | ||
76 | * . | ||
77 | * ^ | ||
78 | * ^ | ||
79 | * ^ | ||
80 | * imx6_suspend code | ||
81 | * PM_INFO structure(imx6_cpu_pm_info) | ||
82 | * ======================== low address ======================= | ||
83 | */ | ||
84 | |||
85 | struct imx6_pm_base { | ||
86 | phys_addr_t pbase; | ||
87 | void __iomem *vbase; | ||
88 | }; | ||
89 | |||
90 | struct imx6_pm_socdata { | ||
91 | u32 cpu_type; | ||
92 | const char *mmdc_compat; | ||
93 | const char *src_compat; | ||
94 | const char *iomuxc_compat; | ||
95 | const char *gpc_compat; | ||
96 | const u32 mmdc_io_num; | ||
97 | const u32 *mmdc_io_offset; | ||
98 | }; | ||
99 | |||
100 | static const u32 imx6q_mmdc_io_offset[] __initconst = { | ||
101 | 0x5ac, 0x5b4, 0x528, 0x520, /* DQM0 ~ DQM3 */ | ||
102 | 0x514, 0x510, 0x5bc, 0x5c4, /* DQM4 ~ DQM7 */ | ||
103 | 0x56c, 0x578, 0x588, 0x594, /* CAS, RAS, SDCLK_0, SDCLK_1 */ | ||
104 | 0x5a8, 0x5b0, 0x524, 0x51c, /* SDQS0 ~ SDQS3 */ | ||
105 | 0x518, 0x50c, 0x5b8, 0x5c0, /* SDQS4 ~ SDQS7 */ | ||
106 | 0x784, 0x788, 0x794, 0x79c, /* GPR_B0DS ~ GPR_B3DS */ | ||
107 | 0x7a0, 0x7a4, 0x7a8, 0x748, /* GPR_B4DS ~ GPR_B7DS */ | ||
108 | 0x59c, 0x5a0, 0x750, 0x774, /* SODT0, SODT1, MODE_CTL, MODE */ | ||
109 | 0x74c, /* GPR_ADDS */ | ||
110 | }; | ||
111 | |||
112 | static const u32 imx6dl_mmdc_io_offset[] __initconst = { | ||
113 | 0x470, 0x474, 0x478, 0x47c, /* DQM0 ~ DQM3 */ | ||
114 | 0x480, 0x484, 0x488, 0x48c, /* DQM4 ~ DQM7 */ | ||
115 | 0x464, 0x490, 0x4ac, 0x4b0, /* CAS, RAS, SDCLK_0, SDCLK_1 */ | ||
116 | 0x4bc, 0x4c0, 0x4c4, 0x4c8, /* DRAM_SDQS0 ~ DRAM_SDQS3 */ | ||
117 | 0x4cc, 0x4d0, 0x4d4, 0x4d8, /* DRAM_SDQS4 ~ DRAM_SDQS7 */ | ||
118 | 0x764, 0x770, 0x778, 0x77c, /* GPR_B0DS ~ GPR_B3DS */ | ||
119 | 0x780, 0x784, 0x78c, 0x748, /* GPR_B4DS ~ GPR_B7DS */ | ||
120 | 0x4b4, 0x4b8, 0x750, 0x760, /* SODT0, SODT1, MODE_CTL, MODE */ | ||
121 | 0x74c, /* GPR_ADDS */ | ||
122 | }; | ||
123 | |||
124 | static const u32 imx6sl_mmdc_io_offset[] __initconst = { | ||
125 | 0x30c, 0x310, 0x314, 0x318, /* DQM0 ~ DQM3 */ | ||
126 | 0x5c4, 0x5cc, 0x5d4, 0x5d8, /* GPR_B0DS ~ GPR_B3DS */ | ||
127 | 0x300, 0x31c, 0x338, 0x5ac, /* CAS, RAS, SDCLK_0, GPR_ADDS */ | ||
128 | 0x33c, 0x340, 0x5b0, 0x5c0, /* SODT0, SODT1, MODE_CTL, MODE */ | ||
129 | 0x330, 0x334, 0x320, /* SDCKE0, SDCKE1, RESET */ | ||
130 | }; | ||
131 | |||
132 | static const struct imx6_pm_socdata imx6q_pm_data __initconst = { | ||
133 | .cpu_type = MXC_CPU_IMX6Q, | ||
134 | .mmdc_compat = "fsl,imx6q-mmdc", | ||
135 | .src_compat = "fsl,imx6q-src", | ||
136 | .iomuxc_compat = "fsl,imx6q-iomuxc", | ||
137 | .gpc_compat = "fsl,imx6q-gpc", | ||
138 | .mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset), | ||
139 | .mmdc_io_offset = imx6q_mmdc_io_offset, | ||
140 | }; | ||
141 | |||
142 | static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { | ||
143 | .cpu_type = MXC_CPU_IMX6DL, | ||
144 | .mmdc_compat = "fsl,imx6q-mmdc", | ||
145 | .src_compat = "fsl,imx6q-src", | ||
146 | .iomuxc_compat = "fsl,imx6dl-iomuxc", | ||
147 | .gpc_compat = "fsl,imx6q-gpc", | ||
148 | .mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset), | ||
149 | .mmdc_io_offset = imx6dl_mmdc_io_offset, | ||
150 | }; | ||
151 | |||
152 | static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { | ||
153 | .cpu_type = MXC_CPU_IMX6SL, | ||
154 | .mmdc_compat = "fsl,imx6sl-mmdc", | ||
155 | .src_compat = "fsl,imx6sl-src", | ||
156 | .iomuxc_compat = "fsl,imx6sl-iomuxc", | ||
157 | .gpc_compat = "fsl,imx6sl-gpc", | ||
158 | .mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset), | ||
159 | .mmdc_io_offset = imx6sl_mmdc_io_offset, | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * This structure is for passing necessary data for low level ocram | ||
164 | * suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct | ||
165 | * definition is changed, the offset definition in | ||
166 | * arch/arm/mach-imx/suspend-imx6.S must be also changed accordingly, | ||
167 | * otherwise, the suspend to ocram function will be broken! | ||
168 | */ | ||
169 | struct imx6_cpu_pm_info { | ||
170 | phys_addr_t pbase; /* The physical address of pm_info. */ | ||
171 | phys_addr_t resume_addr; /* The physical resume address for asm code */ | ||
172 | u32 cpu_type; | ||
173 | u32 pm_info_size; /* Size of pm_info. */ | ||
174 | struct imx6_pm_base mmdc_base; | ||
175 | struct imx6_pm_base src_base; | ||
176 | struct imx6_pm_base iomuxc_base; | ||
177 | struct imx6_pm_base ccm_base; | ||
178 | struct imx6_pm_base gpc_base; | ||
179 | struct imx6_pm_base l2_base; | ||
180 | u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ | ||
181 | u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */ | ||
182 | } __aligned(8); | ||
183 | |||
184 | void imx6q_set_int_mem_clk_lpm(void) | ||
185 | { | ||
186 | u32 val = readl_relaxed(ccm_base + CGPR); | ||
187 | |||
188 | val |= BM_CGPR_INT_MEM_CLK_LPM; | ||
189 | writel_relaxed(val, ccm_base + CGPR); | ||
190 | } | ||
191 | |||
192 | static void imx6q_enable_rbc(bool enable) | ||
193 | { | ||
194 | u32 val; | ||
195 | |||
196 | /* | ||
197 | * need to mask all interrupts in GPC before | ||
198 | * operating RBC configurations | ||
199 | */ | ||
200 | imx_gpc_mask_all(); | ||
201 | |||
202 | /* configure RBC enable bit */ | ||
203 | val = readl_relaxed(ccm_base + CCR); | ||
204 | val &= ~BM_CCR_RBC_EN; | ||
205 | val |= enable ? BM_CCR_RBC_EN : 0; | ||
206 | writel_relaxed(val, ccm_base + CCR); | ||
207 | |||
208 | /* configure RBC count */ | ||
209 | val = readl_relaxed(ccm_base + CCR); | ||
210 | val &= ~BM_CCR_RBC_BYPASS_COUNT; | ||
211 | val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; | ||
212 | writel(val, ccm_base + CCR); | ||
213 | |||
214 | /* | ||
215 | * need to delay at least 2 cycles of CKIL(32K) | ||
216 | * due to hardware design requirement, which is | ||
217 | * ~61us, here we use 65us for safe | ||
218 | */ | ||
219 | udelay(65); | ||
220 | |||
221 | /* restore GPC interrupt mask settings */ | ||
222 | imx_gpc_restore_all(); | ||
223 | } | ||
224 | |||
225 | static void imx6q_enable_wb(bool enable) | ||
226 | { | ||
227 | u32 val; | ||
228 | |||
229 | /* configure well bias enable bit */ | ||
230 | val = readl_relaxed(ccm_base + CLPCR); | ||
231 | val &= ~BM_CLPCR_WB_PER_AT_LPM; | ||
232 | val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; | ||
233 | writel_relaxed(val, ccm_base + CLPCR); | ||
234 | |||
235 | /* configure well bias count */ | ||
236 | val = readl_relaxed(ccm_base + CCR); | ||
237 | val &= ~BM_CCR_WB_COUNT; | ||
238 | val |= enable ? BM_CCR_WB_COUNT : 0; | ||
239 | writel_relaxed(val, ccm_base + CCR); | ||
240 | } | ||
241 | |||
242 | int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) | ||
243 | { | ||
244 | struct irq_data *iomuxc_irq_data = irq_get_irq_data(32); | ||
245 | u32 val = readl_relaxed(ccm_base + CLPCR); | ||
246 | |||
247 | val &= ~BM_CLPCR_LPM; | ||
248 | switch (mode) { | ||
249 | case WAIT_CLOCKED: | ||
250 | break; | ||
251 | case WAIT_UNCLOCKED: | ||
252 | val |= 0x1 << BP_CLPCR_LPM; | ||
253 | val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM; | ||
254 | break; | ||
255 | case STOP_POWER_ON: | ||
256 | val |= 0x2 << BP_CLPCR_LPM; | ||
257 | break; | ||
258 | case WAIT_UNCLOCKED_POWER_OFF: | ||
259 | val |= 0x1 << BP_CLPCR_LPM; | ||
260 | val &= ~BM_CLPCR_VSTBY; | ||
261 | val &= ~BM_CLPCR_SBYOS; | ||
262 | break; | ||
263 | case STOP_POWER_OFF: | ||
264 | val |= 0x2 << BP_CLPCR_LPM; | ||
265 | val |= 0x3 << BP_CLPCR_STBY_COUNT; | ||
266 | val |= BM_CLPCR_VSTBY; | ||
267 | val |= BM_CLPCR_SBYOS; | ||
268 | if (cpu_is_imx6sl()) { | ||
269 | val |= BM_CLPCR_BYPASS_PMIC_READY; | ||
270 | val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; | ||
271 | } else { | ||
272 | val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; | ||
273 | } | ||
274 | break; | ||
275 | default: | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * ERR007265: CCM: When improper low-power sequence is used, | ||
281 | * the SoC enters low power mode before the ARM core executes WFI. | ||
282 | * | ||
283 | * Software workaround: | ||
284 | * 1) Software should trigger IRQ #32 (IOMUX) to be always pending | ||
285 | * by setting IOMUX_GPR1_GINT. | ||
286 | * 2) Software should then unmask IRQ #32 in GPC before setting CCM | ||
287 | * Low-Power mode. | ||
288 | * 3) Software should mask IRQ #32 right after CCM Low-Power mode | ||
289 | * is set (set bits 0-1 of CCM_CLPCR). | ||
290 | */ | ||
291 | imx_gpc_irq_unmask(iomuxc_irq_data); | ||
292 | writel_relaxed(val, ccm_base + CLPCR); | ||
293 | imx_gpc_irq_mask(iomuxc_irq_data); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int imx6q_suspend_finish(unsigned long val) | ||
299 | { | ||
300 | if (!imx6_suspend_in_ocram_fn) { | ||
301 | cpu_do_idle(); | ||
302 | } else { | ||
303 | /* | ||
304 | * call low level suspend function in ocram, | ||
305 | * as we need to float DDR IO. | ||
306 | */ | ||
307 | local_flush_tlb_all(); | ||
308 | imx6_suspend_in_ocram_fn(suspend_ocram_base); | ||
309 | } | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int imx6q_pm_enter(suspend_state_t state) | ||
315 | { | ||
316 | switch (state) { | ||
317 | case PM_SUSPEND_MEM: | ||
318 | imx6q_set_lpm(STOP_POWER_OFF); | ||
319 | imx6q_enable_wb(true); | ||
320 | /* | ||
321 | * For suspend into ocram, asm code already take care of | ||
322 | * RBC setting, so we do NOT need to do that here. | ||
323 | */ | ||
324 | if (!imx6_suspend_in_ocram_fn) | ||
325 | imx6q_enable_rbc(true); | ||
326 | imx_gpc_pre_suspend(); | ||
327 | imx_anatop_pre_suspend(); | ||
328 | imx_set_cpu_jump(0, v7_cpu_resume); | ||
329 | /* Zzz ... */ | ||
330 | cpu_suspend(0, imx6q_suspend_finish); | ||
331 | if (cpu_is_imx6q() || cpu_is_imx6dl()) | ||
332 | imx_smp_prepare(); | ||
333 | imx_anatop_post_resume(); | ||
334 | imx_gpc_post_resume(); | ||
335 | imx6q_enable_rbc(false); | ||
336 | imx6q_enable_wb(false); | ||
337 | imx6q_set_lpm(WAIT_CLOCKED); | ||
338 | break; | ||
339 | default: | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static const struct platform_suspend_ops imx6q_pm_ops = { | ||
347 | .enter = imx6q_pm_enter, | ||
348 | .valid = suspend_valid_only_mem, | ||
349 | }; | ||
350 | |||
351 | void __init imx6q_pm_set_ccm_base(void __iomem *base) | ||
352 | { | ||
353 | ccm_base = base; | ||
354 | } | ||
355 | |||
356 | static int __init imx6_pm_get_base(struct imx6_pm_base *base, | ||
357 | const char *compat) | ||
358 | { | ||
359 | struct device_node *node; | ||
360 | struct resource res; | ||
361 | int ret = 0; | ||
362 | |||
363 | node = of_find_compatible_node(NULL, NULL, compat); | ||
364 | if (!node) { | ||
365 | ret = -ENODEV; | ||
366 | goto out; | ||
367 | } | ||
368 | |||
369 | ret = of_address_to_resource(node, 0, &res); | ||
370 | if (ret) | ||
371 | goto put_node; | ||
372 | |||
373 | base->pbase = res.start; | ||
374 | base->vbase = ioremap(res.start, resource_size(&res)); | ||
375 | if (!base->vbase) | ||
376 | ret = -ENOMEM; | ||
377 | |||
378 | put_node: | ||
379 | of_node_put(node); | ||
380 | out: | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) | ||
385 | { | ||
386 | phys_addr_t ocram_pbase; | ||
387 | struct device_node *node; | ||
388 | struct platform_device *pdev; | ||
389 | struct imx6_cpu_pm_info *pm_info; | ||
390 | struct gen_pool *ocram_pool; | ||
391 | unsigned long ocram_base; | ||
392 | int i, ret = 0; | ||
393 | const u32 *mmdc_offset_array; | ||
394 | |||
395 | suspend_set_ops(&imx6q_pm_ops); | ||
396 | |||
397 | if (!socdata) { | ||
398 | pr_warn("%s: invalid argument!\n", __func__); | ||
399 | return -EINVAL; | ||
400 | } | ||
401 | |||
402 | node = of_find_compatible_node(NULL, NULL, "mmio-sram"); | ||
403 | if (!node) { | ||
404 | pr_warn("%s: failed to find ocram node!\n", __func__); | ||
405 | return -ENODEV; | ||
406 | } | ||
407 | |||
408 | pdev = of_find_device_by_node(node); | ||
409 | if (!pdev) { | ||
410 | pr_warn("%s: failed to find ocram device!\n", __func__); | ||
411 | ret = -ENODEV; | ||
412 | goto put_node; | ||
413 | } | ||
414 | |||
415 | ocram_pool = dev_get_gen_pool(&pdev->dev); | ||
416 | if (!ocram_pool) { | ||
417 | pr_warn("%s: ocram pool unavailable!\n", __func__); | ||
418 | ret = -ENODEV; | ||
419 | goto put_node; | ||
420 | } | ||
421 | |||
422 | ocram_base = gen_pool_alloc(ocram_pool, MX6Q_SUSPEND_OCRAM_SIZE); | ||
423 | if (!ocram_base) { | ||
424 | pr_warn("%s: unable to alloc ocram!\n", __func__); | ||
425 | ret = -ENOMEM; | ||
426 | goto put_node; | ||
427 | } | ||
428 | |||
429 | ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base); | ||
430 | |||
431 | suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, | ||
432 | MX6Q_SUSPEND_OCRAM_SIZE, false); | ||
433 | |||
434 | pm_info = suspend_ocram_base; | ||
435 | pm_info->pbase = ocram_pbase; | ||
436 | pm_info->resume_addr = virt_to_phys(v7_cpu_resume); | ||
437 | pm_info->pm_info_size = sizeof(*pm_info); | ||
438 | |||
439 | /* | ||
440 | * ccm physical address is not used by asm code currently, | ||
441 | * so get ccm virtual address directly, as we already have | ||
442 | * it from ccm driver. | ||
443 | */ | ||
444 | pm_info->ccm_base.vbase = ccm_base; | ||
445 | |||
446 | ret = imx6_pm_get_base(&pm_info->mmdc_base, socdata->mmdc_compat); | ||
447 | if (ret) { | ||
448 | pr_warn("%s: failed to get mmdc base %d!\n", __func__, ret); | ||
449 | goto put_node; | ||
450 | } | ||
451 | |||
452 | ret = imx6_pm_get_base(&pm_info->src_base, socdata->src_compat); | ||
453 | if (ret) { | ||
454 | pr_warn("%s: failed to get src base %d!\n", __func__, ret); | ||
455 | goto src_map_failed; | ||
456 | } | ||
457 | |||
458 | ret = imx6_pm_get_base(&pm_info->iomuxc_base, socdata->iomuxc_compat); | ||
459 | if (ret) { | ||
460 | pr_warn("%s: failed to get iomuxc base %d!\n", __func__, ret); | ||
461 | goto iomuxc_map_failed; | ||
462 | } | ||
463 | |||
464 | ret = imx6_pm_get_base(&pm_info->gpc_base, socdata->gpc_compat); | ||
465 | if (ret) { | ||
466 | pr_warn("%s: failed to get gpc base %d!\n", __func__, ret); | ||
467 | goto gpc_map_failed; | ||
468 | } | ||
469 | |||
470 | ret = imx6_pm_get_base(&pm_info->l2_base, "arm,pl310-cache"); | ||
471 | if (ret) { | ||
472 | pr_warn("%s: failed to get pl310-cache base %d!\n", | ||
473 | __func__, ret); | ||
474 | goto pl310_cache_map_failed; | ||
475 | } | ||
476 | |||
477 | pm_info->cpu_type = socdata->cpu_type; | ||
478 | pm_info->mmdc_io_num = socdata->mmdc_io_num; | ||
479 | mmdc_offset_array = socdata->mmdc_io_offset; | ||
480 | |||
481 | for (i = 0; i < pm_info->mmdc_io_num; i++) { | ||
482 | pm_info->mmdc_io_val[i][0] = | ||
483 | mmdc_offset_array[i]; | ||
484 | pm_info->mmdc_io_val[i][1] = | ||
485 | readl_relaxed(pm_info->iomuxc_base.vbase + | ||
486 | mmdc_offset_array[i]); | ||
487 | } | ||
488 | |||
489 | imx6_suspend_in_ocram_fn = fncpy( | ||
490 | suspend_ocram_base + sizeof(*pm_info), | ||
491 | &imx6_suspend, | ||
492 | MX6Q_SUSPEND_OCRAM_SIZE - sizeof(*pm_info)); | ||
493 | |||
494 | goto put_node; | ||
495 | |||
496 | pl310_cache_map_failed: | ||
497 | iounmap(&pm_info->gpc_base.vbase); | ||
498 | gpc_map_failed: | ||
499 | iounmap(&pm_info->iomuxc_base.vbase); | ||
500 | iomuxc_map_failed: | ||
501 | iounmap(&pm_info->src_base.vbase); | ||
502 | src_map_failed: | ||
503 | iounmap(&pm_info->mmdc_base.vbase); | ||
504 | put_node: | ||
505 | of_node_put(node); | ||
506 | |||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | static void __init imx6_pm_common_init(const struct imx6_pm_socdata | ||
511 | *socdata) | ||
512 | { | ||
513 | struct regmap *gpr; | ||
514 | int ret; | ||
515 | |||
516 | WARN_ON(!ccm_base); | ||
517 | |||
518 | if (IS_ENABLED(CONFIG_SUSPEND)) { | ||
519 | ret = imx6q_suspend_init(socdata); | ||
520 | if (ret) | ||
521 | pr_warn("%s: No DDR LPM support with suspend %d!\n", | ||
522 | __func__, ret); | ||
523 | } | ||
524 | |||
525 | /* | ||
526 | * This is for SW workaround step #1 of ERR007265, see comments | ||
527 | * in imx6q_set_lpm for details of this errata. | ||
528 | * Force IOMUXC irq pending, so that the interrupt to GPC can be | ||
529 | * used to deassert dsm_request signal when the signal gets | ||
530 | * asserted unexpectedly. | ||
531 | */ | ||
532 | gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); | ||
533 | if (!IS_ERR(gpr)) | ||
534 | regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT, | ||
535 | IMX6Q_GPR1_GINT); | ||
536 | } | ||
537 | |||
538 | void __init imx6q_pm_init(void) | ||
539 | { | ||
540 | imx6_pm_common_init(&imx6q_pm_data); | ||
541 | } | ||
542 | |||
543 | void __init imx6dl_pm_init(void) | ||
544 | { | ||
545 | imx6_pm_common_init(&imx6dl_pm_data); | ||
546 | } | ||
547 | |||
548 | void __init imx6sl_pm_init(void) | ||
549 | { | ||
550 | imx6_pm_common_init(&imx6sl_pm_data); | ||
551 | } | ||
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c deleted file mode 100644 index 29e3fe6a6669..000000000000 --- a/arch/arm/mach-imx/pm-imx6q.c +++ /dev/null | |||
@@ -1,240 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2013 Freescale Semiconductor, Inc. | ||
3 | * Copyright 2011 Linaro Ltd. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/mfd/syscon.h> | ||
18 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_address.h> | ||
21 | #include <linux/regmap.h> | ||
22 | #include <linux/suspend.h> | ||
23 | #include <asm/cacheflush.h> | ||
24 | #include <asm/proc-fns.h> | ||
25 | #include <asm/suspend.h> | ||
26 | #include <asm/hardware/cache-l2x0.h> | ||
27 | |||
28 | #include "common.h" | ||
29 | #include "hardware.h" | ||
30 | |||
31 | #define CCR 0x0 | ||
32 | #define BM_CCR_WB_COUNT (0x7 << 16) | ||
33 | #define BM_CCR_RBC_BYPASS_COUNT (0x3f << 21) | ||
34 | #define BM_CCR_RBC_EN (0x1 << 27) | ||
35 | |||
36 | #define CLPCR 0x54 | ||
37 | #define BP_CLPCR_LPM 0 | ||
38 | #define BM_CLPCR_LPM (0x3 << 0) | ||
39 | #define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) | ||
40 | #define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) | ||
41 | #define BM_CLPCR_SBYOS (0x1 << 6) | ||
42 | #define BM_CLPCR_DIS_REF_OSC (0x1 << 7) | ||
43 | #define BM_CLPCR_VSTBY (0x1 << 8) | ||
44 | #define BP_CLPCR_STBY_COUNT 9 | ||
45 | #define BM_CLPCR_STBY_COUNT (0x3 << 9) | ||
46 | #define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) | ||
47 | #define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) | ||
48 | #define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) | ||
49 | #define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) | ||
50 | #define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) | ||
51 | #define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) | ||
52 | #define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) | ||
53 | #define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) | ||
54 | #define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) | ||
55 | #define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) | ||
56 | #define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) | ||
57 | |||
58 | #define CGPR 0x64 | ||
59 | #define BM_CGPR_CHICKEN_BIT (0x1 << 17) | ||
60 | |||
61 | static void __iomem *ccm_base; | ||
62 | |||
63 | void imx6q_set_chicken_bit(void) | ||
64 | { | ||
65 | u32 val = readl_relaxed(ccm_base + CGPR); | ||
66 | |||
67 | val |= BM_CGPR_CHICKEN_BIT; | ||
68 | writel_relaxed(val, ccm_base + CGPR); | ||
69 | } | ||
70 | |||
71 | static void imx6q_enable_rbc(bool enable) | ||
72 | { | ||
73 | u32 val; | ||
74 | |||
75 | /* | ||
76 | * need to mask all interrupts in GPC before | ||
77 | * operating RBC configurations | ||
78 | */ | ||
79 | imx_gpc_mask_all(); | ||
80 | |||
81 | /* configure RBC enable bit */ | ||
82 | val = readl_relaxed(ccm_base + CCR); | ||
83 | val &= ~BM_CCR_RBC_EN; | ||
84 | val |= enable ? BM_CCR_RBC_EN : 0; | ||
85 | writel_relaxed(val, ccm_base + CCR); | ||
86 | |||
87 | /* configure RBC count */ | ||
88 | val = readl_relaxed(ccm_base + CCR); | ||
89 | val &= ~BM_CCR_RBC_BYPASS_COUNT; | ||
90 | val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; | ||
91 | writel(val, ccm_base + CCR); | ||
92 | |||
93 | /* | ||
94 | * need to delay at least 2 cycles of CKIL(32K) | ||
95 | * due to hardware design requirement, which is | ||
96 | * ~61us, here we use 65us for safe | ||
97 | */ | ||
98 | udelay(65); | ||
99 | |||
100 | /* restore GPC interrupt mask settings */ | ||
101 | imx_gpc_restore_all(); | ||
102 | } | ||
103 | |||
104 | static void imx6q_enable_wb(bool enable) | ||
105 | { | ||
106 | u32 val; | ||
107 | |||
108 | /* configure well bias enable bit */ | ||
109 | val = readl_relaxed(ccm_base + CLPCR); | ||
110 | val &= ~BM_CLPCR_WB_PER_AT_LPM; | ||
111 | val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; | ||
112 | writel_relaxed(val, ccm_base + CLPCR); | ||
113 | |||
114 | /* configure well bias count */ | ||
115 | val = readl_relaxed(ccm_base + CCR); | ||
116 | val &= ~BM_CCR_WB_COUNT; | ||
117 | val |= enable ? BM_CCR_WB_COUNT : 0; | ||
118 | writel_relaxed(val, ccm_base + CCR); | ||
119 | } | ||
120 | |||
121 | int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) | ||
122 | { | ||
123 | struct irq_data *iomuxc_irq_data = irq_get_irq_data(32); | ||
124 | u32 val = readl_relaxed(ccm_base + CLPCR); | ||
125 | |||
126 | val &= ~BM_CLPCR_LPM; | ||
127 | switch (mode) { | ||
128 | case WAIT_CLOCKED: | ||
129 | break; | ||
130 | case WAIT_UNCLOCKED: | ||
131 | val |= 0x1 << BP_CLPCR_LPM; | ||
132 | val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM; | ||
133 | break; | ||
134 | case STOP_POWER_ON: | ||
135 | val |= 0x2 << BP_CLPCR_LPM; | ||
136 | break; | ||
137 | case WAIT_UNCLOCKED_POWER_OFF: | ||
138 | val |= 0x1 << BP_CLPCR_LPM; | ||
139 | val &= ~BM_CLPCR_VSTBY; | ||
140 | val &= ~BM_CLPCR_SBYOS; | ||
141 | break; | ||
142 | case STOP_POWER_OFF: | ||
143 | val |= 0x2 << BP_CLPCR_LPM; | ||
144 | val |= 0x3 << BP_CLPCR_STBY_COUNT; | ||
145 | val |= BM_CLPCR_VSTBY; | ||
146 | val |= BM_CLPCR_SBYOS; | ||
147 | if (cpu_is_imx6sl()) { | ||
148 | val |= BM_CLPCR_BYPASS_PMIC_READY; | ||
149 | val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; | ||
150 | } else { | ||
151 | val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; | ||
152 | } | ||
153 | break; | ||
154 | default: | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * ERR007265: CCM: When improper low-power sequence is used, | ||
160 | * the SoC enters low power mode before the ARM core executes WFI. | ||
161 | * | ||
162 | * Software workaround: | ||
163 | * 1) Software should trigger IRQ #32 (IOMUX) to be always pending | ||
164 | * by setting IOMUX_GPR1_GINT. | ||
165 | * 2) Software should then unmask IRQ #32 in GPC before setting CCM | ||
166 | * Low-Power mode. | ||
167 | * 3) Software should mask IRQ #32 right after CCM Low-Power mode | ||
168 | * is set (set bits 0-1 of CCM_CLPCR). | ||
169 | */ | ||
170 | imx_gpc_irq_unmask(iomuxc_irq_data); | ||
171 | writel_relaxed(val, ccm_base + CLPCR); | ||
172 | imx_gpc_irq_mask(iomuxc_irq_data); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int imx6q_suspend_finish(unsigned long val) | ||
178 | { | ||
179 | cpu_do_idle(); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int imx6q_pm_enter(suspend_state_t state) | ||
184 | { | ||
185 | switch (state) { | ||
186 | case PM_SUSPEND_MEM: | ||
187 | imx6q_set_lpm(STOP_POWER_OFF); | ||
188 | imx6q_enable_wb(true); | ||
189 | imx6q_enable_rbc(true); | ||
190 | imx_gpc_pre_suspend(); | ||
191 | imx_anatop_pre_suspend(); | ||
192 | imx_set_cpu_jump(0, v7_cpu_resume); | ||
193 | /* Zzz ... */ | ||
194 | cpu_suspend(0, imx6q_suspend_finish); | ||
195 | if (cpu_is_imx6q() || cpu_is_imx6dl()) | ||
196 | imx_smp_prepare(); | ||
197 | imx_anatop_post_resume(); | ||
198 | imx_gpc_post_resume(); | ||
199 | imx6q_enable_rbc(false); | ||
200 | imx6q_enable_wb(false); | ||
201 | imx6q_set_lpm(WAIT_CLOCKED); | ||
202 | break; | ||
203 | default: | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static const struct platform_suspend_ops imx6q_pm_ops = { | ||
211 | .enter = imx6q_pm_enter, | ||
212 | .valid = suspend_valid_only_mem, | ||
213 | }; | ||
214 | |||
215 | void __init imx6q_pm_set_ccm_base(void __iomem *base) | ||
216 | { | ||
217 | ccm_base = base; | ||
218 | } | ||
219 | |||
220 | void __init imx6q_pm_init(void) | ||
221 | { | ||
222 | struct regmap *gpr; | ||
223 | |||
224 | WARN_ON(!ccm_base); | ||
225 | |||
226 | /* | ||
227 | * This is for SW workaround step #1 of ERR007265, see comments | ||
228 | * in imx6q_set_lpm for details of this errata. | ||
229 | * Force IOMUXC irq pending, so that the interrupt to GPC can be | ||
230 | * used to deassert dsm_request signal when the signal gets | ||
231 | * asserted unexpectedly. | ||
232 | */ | ||
233 | gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); | ||
234 | if (!IS_ERR(gpr)) | ||
235 | regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT, | ||
236 | IMX6Q_GPR1_GINT); | ||
237 | |||
238 | |||
239 | suspend_set_ops(&imx6q_pm_ops); | ||
240 | } | ||
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S new file mode 100644 index 000000000000..20048ff05739 --- /dev/null +++ b/arch/arm/mach-imx/suspend-imx6.S | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * Copyright 2014 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * 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 | * Version 2 or later at the following locations: | ||
7 | * | ||
8 | * http://www.opensource.org/licenses/gpl-license.html | ||
9 | * http://www.gnu.org/copyleft/gpl.html | ||
10 | */ | ||
11 | |||
12 | #include <linux/linkage.h> | ||
13 | #include <asm/asm-offsets.h> | ||
14 | #include <asm/hardware/cache-l2x0.h> | ||
15 | #include "hardware.h" | ||
16 | |||
17 | /* | ||
18 | * ==================== low level suspend ==================== | ||
19 | * | ||
20 | * Better to follow below rules to use ARM registers: | ||
21 | * r0: pm_info structure address; | ||
22 | * r1 ~ r4: for saving pm_info members; | ||
23 | * r5 ~ r10: free registers; | ||
24 | * r11: io base address. | ||
25 | * | ||
26 | * suspend ocram space layout: | ||
27 | * ======================== high address ====================== | ||
28 | * . | ||
29 | * . | ||
30 | * . | ||
31 | * ^ | ||
32 | * ^ | ||
33 | * ^ | ||
34 | * imx6_suspend code | ||
35 | * PM_INFO structure(imx6_cpu_pm_info) | ||
36 | * ======================== low address ======================= | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * Below offsets are based on struct imx6_cpu_pm_info | ||
41 | * which defined in arch/arm/mach-imx/pm-imx6q.c, this | ||
42 | * structure contains necessary pm info for low level | ||
43 | * suspend related code. | ||
44 | */ | ||
45 | #define PM_INFO_PBASE_OFFSET 0x0 | ||
46 | #define PM_INFO_RESUME_ADDR_OFFSET 0x4 | ||
47 | #define PM_INFO_CPU_TYPE_OFFSET 0x8 | ||
48 | #define PM_INFO_PM_INFO_SIZE_OFFSET 0xC | ||
49 | #define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 | ||
50 | #define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 | ||
51 | #define PM_INFO_MX6Q_SRC_P_OFFSET 0x18 | ||
52 | #define PM_INFO_MX6Q_SRC_V_OFFSET 0x1C | ||
53 | #define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x20 | ||
54 | #define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x24 | ||
55 | #define PM_INFO_MX6Q_CCM_P_OFFSET 0x28 | ||
56 | #define PM_INFO_MX6Q_CCM_V_OFFSET 0x2C | ||
57 | #define PM_INFO_MX6Q_GPC_P_OFFSET 0x30 | ||
58 | #define PM_INFO_MX6Q_GPC_V_OFFSET 0x34 | ||
59 | #define PM_INFO_MX6Q_L2_P_OFFSET 0x38 | ||
60 | #define PM_INFO_MX6Q_L2_V_OFFSET 0x3C | ||
61 | #define PM_INFO_MMDC_IO_NUM_OFFSET 0x40 | ||
62 | #define PM_INFO_MMDC_IO_VAL_OFFSET 0x44 | ||
63 | |||
64 | #define MX6Q_SRC_GPR1 0x20 | ||
65 | #define MX6Q_SRC_GPR2 0x24 | ||
66 | #define MX6Q_MMDC_MAPSR 0x404 | ||
67 | #define MX6Q_MMDC_MPDGCTRL0 0x83c | ||
68 | #define MX6Q_GPC_IMR1 0x08 | ||
69 | #define MX6Q_GPC_IMR2 0x0c | ||
70 | #define MX6Q_GPC_IMR3 0x10 | ||
71 | #define MX6Q_GPC_IMR4 0x14 | ||
72 | #define MX6Q_CCM_CCR 0x0 | ||
73 | |||
74 | .align 3 | ||
75 | |||
76 | .macro sync_l2_cache | ||
77 | |||
78 | /* sync L2 cache to drain L2's buffers to DRAM. */ | ||
79 | #ifdef CONFIG_CACHE_L2X0 | ||
80 | ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] | ||
81 | mov r6, #0x0 | ||
82 | str r6, [r11, #L2X0_CACHE_SYNC] | ||
83 | 1: | ||
84 | ldr r6, [r11, #L2X0_CACHE_SYNC] | ||
85 | ands r6, r6, #0x1 | ||
86 | bne 1b | ||
87 | #endif | ||
88 | |||
89 | .endm | ||
90 | |||
91 | .macro resume_mmdc | ||
92 | |||
93 | /* restore MMDC IO */ | ||
94 | cmp r5, #0x0 | ||
95 | ldreq r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] | ||
96 | ldrne r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] | ||
97 | |||
98 | ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] | ||
99 | ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET | ||
100 | add r7, r7, r0 | ||
101 | 1: | ||
102 | ldr r8, [r7], #0x4 | ||
103 | ldr r9, [r7], #0x4 | ||
104 | str r9, [r11, r8] | ||
105 | subs r6, r6, #0x1 | ||
106 | bne 1b | ||
107 | |||
108 | cmp r5, #0x0 | ||
109 | ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] | ||
110 | ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] | ||
111 | |||
112 | cmp r3, #MXC_CPU_IMX6SL | ||
113 | bne 4f | ||
114 | |||
115 | /* reset read FIFO, RST_RD_FIFO */ | ||
116 | ldr r7, =MX6Q_MMDC_MPDGCTRL0 | ||
117 | ldr r6, [r11, r7] | ||
118 | orr r6, r6, #(1 << 31) | ||
119 | str r6, [r11, r7] | ||
120 | 2: | ||
121 | ldr r6, [r11, r7] | ||
122 | ands r6, r6, #(1 << 31) | ||
123 | bne 2b | ||
124 | |||
125 | /* reset FIFO a second time */ | ||
126 | ldr r6, [r11, r7] | ||
127 | orr r6, r6, #(1 << 31) | ||
128 | str r6, [r11, r7] | ||
129 | 3: | ||
130 | ldr r6, [r11, r7] | ||
131 | ands r6, r6, #(1 << 31) | ||
132 | bne 3b | ||
133 | 4: | ||
134 | /* let DDR out of self-refresh */ | ||
135 | ldr r7, [r11, #MX6Q_MMDC_MAPSR] | ||
136 | bic r7, r7, #(1 << 21) | ||
137 | str r7, [r11, #MX6Q_MMDC_MAPSR] | ||
138 | 5: | ||
139 | ldr r7, [r11, #MX6Q_MMDC_MAPSR] | ||
140 | ands r7, r7, #(1 << 25) | ||
141 | bne 5b | ||
142 | |||
143 | /* enable DDR auto power saving */ | ||
144 | ldr r7, [r11, #MX6Q_MMDC_MAPSR] | ||
145 | bic r7, r7, #0x1 | ||
146 | str r7, [r11, #MX6Q_MMDC_MAPSR] | ||
147 | |||
148 | .endm | ||
149 | |||
150 | ENTRY(imx6_suspend) | ||
151 | ldr r1, [r0, #PM_INFO_PBASE_OFFSET] | ||
152 | ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] | ||
153 | ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET] | ||
154 | ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] | ||
155 | |||
156 | /* | ||
157 | * counting the resume address in iram | ||
158 | * to set it in SRC register. | ||
159 | */ | ||
160 | ldr r6, =imx6_suspend | ||
161 | ldr r7, =resume | ||
162 | sub r7, r7, r6 | ||
163 | add r8, r1, r4 | ||
164 | add r9, r8, r7 | ||
165 | |||
166 | /* | ||
167 | * make sure TLB contain the addr we want, | ||
168 | * as we will access them after MMDC IO floated. | ||
169 | */ | ||
170 | |||
171 | ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] | ||
172 | ldr r6, [r11, #0x0] | ||
173 | ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] | ||
174 | ldr r6, [r11, #0x0] | ||
175 | |||
176 | /* use r11 to store the IO address */ | ||
177 | ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] | ||
178 | /* store physical resume addr and pm_info address. */ | ||
179 | str r9, [r11, #MX6Q_SRC_GPR1] | ||
180 | str r1, [r11, #MX6Q_SRC_GPR2] | ||
181 | |||
182 | /* need to sync L2 cache before DSM. */ | ||
183 | sync_l2_cache | ||
184 | |||
185 | ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] | ||
186 | /* | ||
187 | * put DDR explicitly into self-refresh and | ||
188 | * disable automatic power savings. | ||
189 | */ | ||
190 | ldr r7, [r11, #MX6Q_MMDC_MAPSR] | ||
191 | orr r7, r7, #0x1 | ||
192 | str r7, [r11, #MX6Q_MMDC_MAPSR] | ||
193 | |||
194 | /* make the DDR explicitly enter self-refresh. */ | ||
195 | ldr r7, [r11, #MX6Q_MMDC_MAPSR] | ||
196 | orr r7, r7, #(1 << 21) | ||
197 | str r7, [r11, #MX6Q_MMDC_MAPSR] | ||
198 | |||
199 | poll_dvfs_set: | ||
200 | ldr r7, [r11, #MX6Q_MMDC_MAPSR] | ||
201 | ands r7, r7, #(1 << 25) | ||
202 | beq poll_dvfs_set | ||
203 | |||
204 | ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] | ||
205 | ldr r6, =0x0 | ||
206 | ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] | ||
207 | ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET | ||
208 | add r8, r8, r0 | ||
209 | /* i.MX6SL's last 3 IOs need special setting */ | ||
210 | cmp r3, #MXC_CPU_IMX6SL | ||
211 | subeq r7, r7, #0x3 | ||
212 | set_mmdc_io_lpm: | ||
213 | ldr r9, [r8], #0x8 | ||
214 | str r6, [r11, r9] | ||
215 | subs r7, r7, #0x1 | ||
216 | bne set_mmdc_io_lpm | ||
217 | |||
218 | cmp r3, #MXC_CPU_IMX6SL | ||
219 | bne set_mmdc_io_lpm_done | ||
220 | ldr r6, =0x1000 | ||
221 | ldr r9, [r8], #0x8 | ||
222 | str r6, [r11, r9] | ||
223 | ldr r9, [r8], #0x8 | ||
224 | str r6, [r11, r9] | ||
225 | ldr r6, =0x80000 | ||
226 | ldr r9, [r8] | ||
227 | str r6, [r11, r9] | ||
228 | set_mmdc_io_lpm_done: | ||
229 | |||
230 | /* | ||
231 | * mask all GPC interrupts before | ||
232 | * enabling the RBC counters to | ||
233 | * avoid the counter starting too | ||
234 | * early if an interupt is already | ||
235 | * pending. | ||
236 | */ | ||
237 | ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] | ||
238 | ldr r6, [r11, #MX6Q_GPC_IMR1] | ||
239 | ldr r7, [r11, #MX6Q_GPC_IMR2] | ||
240 | ldr r8, [r11, #MX6Q_GPC_IMR3] | ||
241 | ldr r9, [r11, #MX6Q_GPC_IMR4] | ||
242 | |||
243 | ldr r10, =0xffffffff | ||
244 | str r10, [r11, #MX6Q_GPC_IMR1] | ||
245 | str r10, [r11, #MX6Q_GPC_IMR2] | ||
246 | str r10, [r11, #MX6Q_GPC_IMR3] | ||
247 | str r10, [r11, #MX6Q_GPC_IMR4] | ||
248 | |||
249 | /* | ||
250 | * enable the RBC bypass counter here | ||
251 | * to hold off the interrupts. RBC counter | ||
252 | * = 32 (1ms), Minimum RBC delay should be | ||
253 | * 400us for the analog LDOs to power down. | ||
254 | */ | ||
255 | ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] | ||
256 | ldr r10, [r11, #MX6Q_CCM_CCR] | ||
257 | bic r10, r10, #(0x3f << 21) | ||
258 | orr r10, r10, #(0x20 << 21) | ||
259 | str r10, [r11, #MX6Q_CCM_CCR] | ||
260 | |||
261 | /* enable the counter. */ | ||
262 | ldr r10, [r11, #MX6Q_CCM_CCR] | ||
263 | orr r10, r10, #(0x1 << 27) | ||
264 | str r10, [r11, #MX6Q_CCM_CCR] | ||
265 | |||
266 | /* unmask all the GPC interrupts. */ | ||
267 | ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] | ||
268 | str r6, [r11, #MX6Q_GPC_IMR1] | ||
269 | str r7, [r11, #MX6Q_GPC_IMR2] | ||
270 | str r8, [r11, #MX6Q_GPC_IMR3] | ||
271 | str r9, [r11, #MX6Q_GPC_IMR4] | ||
272 | |||
273 | /* | ||
274 | * now delay for a short while (3usec) | ||
275 | * ARM is at 1GHz at this point | ||
276 | * so a short loop should be enough. | ||
277 | * this delay is required to ensure that | ||
278 | * the RBC counter can start counting in | ||
279 | * case an interrupt is already pending | ||
280 | * or in case an interrupt arrives just | ||
281 | * as ARM is about to assert DSM_request. | ||
282 | */ | ||
283 | ldr r6, =2000 | ||
284 | rbc_loop: | ||
285 | subs r6, r6, #0x1 | ||
286 | bne rbc_loop | ||
287 | |||
288 | /* Zzz, enter stop mode */ | ||
289 | wfi | ||
290 | nop | ||
291 | nop | ||
292 | nop | ||
293 | nop | ||
294 | |||
295 | /* | ||
296 | * run to here means there is pending | ||
297 | * wakeup source, system should auto | ||
298 | * resume, we need to restore MMDC IO first | ||
299 | */ | ||
300 | mov r5, #0x0 | ||
301 | resume_mmdc | ||
302 | |||
303 | /* return to suspend finish */ | ||
304 | mov pc, lr | ||
305 | |||
306 | resume: | ||
307 | /* invalidate L1 I-cache first */ | ||
308 | mov r6, #0x0 | ||
309 | mcr p15, 0, r6, c7, c5, 0 | ||
310 | mcr p15, 0, r6, c7, c5, 6 | ||
311 | /* enable the Icache and branch prediction */ | ||
312 | mov r6, #0x1800 | ||
313 | mcr p15, 0, r6, c1, c0, 0 | ||
314 | isb | ||
315 | |||
316 | /* get physical resume address from pm_info. */ | ||
317 | ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] | ||
318 | /* clear core0's entry and parameter */ | ||
319 | ldr r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET] | ||
320 | mov r7, #0x0 | ||
321 | str r7, [r11, #MX6Q_SRC_GPR1] | ||
322 | str r7, [r11, #MX6Q_SRC_GPR2] | ||
323 | |||
324 | ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET] | ||
325 | mov r5, #0x1 | ||
326 | resume_mmdc | ||
327 | |||
328 | mov pc, lr | ||
329 | ENDPROC(imx6_suspend) | ||
330 | |||
331 | /* | ||
332 | * The following code must assume it is running from physical address | ||
333 | * where absolute virtual addresses to the data section have to be | ||
334 | * turned into relative ones. | ||
335 | */ | ||
336 | |||
337 | #ifdef CONFIG_CACHE_L2X0 | ||
338 | .macro pl310_resume | ||
339 | adr r0, l2x0_saved_regs_offset | ||
340 | ldr r2, [r0] | ||
341 | add r2, r2, r0 | ||
342 | ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0 | ||
343 | ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value | ||
344 | str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl | ||
345 | mov r1, #0x1 | ||
346 | str r1, [r0, #L2X0_CTRL] @ re-enable L2 | ||
347 | .endm | ||
348 | |||
349 | l2x0_saved_regs_offset: | ||
350 | .word l2x0_saved_regs - . | ||
351 | |||
352 | #else | ||
353 | .macro pl310_resume | ||
354 | .endm | ||
355 | #endif | ||
356 | |||
357 | ENTRY(v7_cpu_resume) | ||
358 | bl v7_invalidate_l1 | ||
359 | pl310_resume | ||
360 | b cpu_resume | ||
361 | ENDPROC(v7_cpu_resume) | ||
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index 1a3a5f615770..65222ea0df6d 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
26 | #include <linux/clockchips.h> | 26 | #include <linux/clockchips.h> |
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | #include <linux/delay.h> | ||
28 | #include <linux/err.h> | 29 | #include <linux/err.h> |
29 | #include <linux/sched_clock.h> | 30 | #include <linux/sched_clock.h> |
30 | 31 | ||
@@ -116,11 +117,22 @@ static u64 notrace mxc_read_sched_clock(void) | |||
116 | return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0; | 117 | return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0; |
117 | } | 118 | } |
118 | 119 | ||
120 | static struct delay_timer imx_delay_timer; | ||
121 | |||
122 | static unsigned long imx_read_current_timer(void) | ||
123 | { | ||
124 | return __raw_readl(sched_clock_reg); | ||
125 | } | ||
126 | |||
119 | static int __init mxc_clocksource_init(struct clk *timer_clk) | 127 | static int __init mxc_clocksource_init(struct clk *timer_clk) |
120 | { | 128 | { |
121 | unsigned int c = clk_get_rate(timer_clk); | 129 | unsigned int c = clk_get_rate(timer_clk); |
122 | void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN); | 130 | void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN); |
123 | 131 | ||
132 | imx_delay_timer.read_current_timer = &imx_read_current_timer; | ||
133 | imx_delay_timer.freq = c; | ||
134 | register_current_timer_delay(&imx_delay_timer); | ||
135 | |||
124 | sched_clock_reg = reg; | 136 | sched_clock_reg = reg; |
125 | 137 | ||
126 | sched_clock_register(mxc_read_sched_clock, 32, c); | 138 | sched_clock_register(mxc_read_sched_clock, 32, c); |