aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>2014-02-13 17:50:20 -0500
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:00 -0400
commit82ec39fe5a2a28c0d384c34e99dcc78a034646e2 (patch)
treeddf60b0c490f62fce204f9776af385c6610098f3
parentb0a7a9c6a4641b3f4bbcd59551b7afc3ed3662a1 (diff)
ENGR00297285-1 [MX6x] Support IRAM page table when DDR is in self-refresh
Whenever DDR is explicitly put into self-refresh, we need to ensure that no access are made to the DDR. All the bus masters excpet ARM are shutdown gracefully. The ARM core can continue to access the DDR due to: 1. Speculative accesses This can be prevented by flushing the Branch Target Address Cache 2. Aggressive Prefetching This can be minimized by adding nops. Apart from this the TLB architecture in ARM does not guarantee that an entry remains in the TLB unless its explicitly locked. Even if free slots are available an entry maybe evicted. So flushing the TLB does not guarantee a page table walk will not happen. The solution is to put a minimized page table in IRAM that can be used when DDR is in self-refresh. The IRAM page tables should have entries for IRAM, AIPS1 and AIPS2 as these entries will be needed by the code that puts DDR into self-refresh. It should not contain any entries that point to the DDR. This patch set accomplishes the following: 1. Set the IRAM to be mapped as 1M sections in the high mem region. This makes it possible to create entries for the IRAM code in the IRAM page table. We need to ensure that both the DDR and IRAM page table have mapping for the IRAM code. 2. Ensure the IRAM, AIPS1, AIPS2 have entries in the IRAM page table. 3. Save TTBR1 4. Set TTBR1 to point to the page tables stored in IRAM. Switch to using TTBR1 before DDR is put into self-refresh. Ensure the following settings: a. TTBCR.N = 1 This means the 0-2G virtual address space is translated using TTBR0 and 2G-4G is translated using TTBR1. b. Set TTBCR.PD0 = 1 With this setting page table walks using TTBR0 are disabled. 4. After the DDR has exited self-refresh, reset TTBCR to 0 (TTBR0 will be used for translations now). 5. Restore TTBR1 Even though TTBR1 is only used to decode the top 2G of virtual address space, ARM requires that we allocate the entire 16KB for the page table. To minimize IRAM/OCRAM required, we put the code in the bottom 8K and page table entries in the top 8K. This requires the low power code be optimized to occupy as little space as possible. This commit is cherry-picked: 93ae491d9dbe34a91e2dd5832b02b0f0a390ddbe Signed-off-by: Ranjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>
-rw-r--r--arch/arm/mach-imx/busfreq_ddr3.c114
-rw-r--r--arch/arm/mach-imx/busfreq_lpddr2.c118
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sl.c69
-rw-r--r--arch/arm/mach-imx/ddr3_freq_imx6.S105
-rw-r--r--arch/arm/mach-imx/hardware.h12
-rw-r--r--arch/arm/mach-imx/imx6sl_wfi.S118
-rw-r--r--arch/arm/mach-imx/lpddr2_freq_imx6.S108
-rw-r--r--arch/arm/mach-imx/mx6.h25
-rw-r--r--arch/arm/mach-imx/pm-imx6.c116
-rw-r--r--arch/arm/mach-imx/suspend-imx6.S50
10 files changed, 446 insertions, 389 deletions
diff --git a/arch/arm/mach-imx/busfreq_ddr3.c b/arch/arm/mach-imx/busfreq_ddr3.c
index 3121e38efaea..c59fd928c385 100644
--- a/arch/arm/mach-imx/busfreq_ddr3.c
+++ b/arch/arm/mach-imx/busfreq_ddr3.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. 2 * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
3 */ 3 */
4 4
5/* 5/*
@@ -49,8 +49,6 @@ static unsigned long (*iram_iomux_settings)[2];
49 49
50static void __iomem *mmdc_base; 50static void __iomem *mmdc_base;
51static void __iomem *iomux_base; 51static void __iomem *iomux_base;
52static void __iomem *ccm_base;
53static void __iomem *l2_base;
54static void __iomem *gic_dist_base; 52static void __iomem *gic_dist_base;
55static u32 *irqs_used; 53static u32 *irqs_used;
56 54
@@ -70,10 +68,11 @@ extern int low_bus_freq_mode;
70extern int audio_bus_freq_mode; 68extern int audio_bus_freq_mode;
71extern void mx6_ddr3_freq_change(u32 freq, void *ddr_settings, 69extern void mx6_ddr3_freq_change(u32 freq, void *ddr_settings,
72 bool dll_mode, void *iomux_offsets); 70 bool dll_mode, void *iomux_offsets);
71extern unsigned long save_ttbr1(void);
72extern void restore_ttbr1(unsigned long ttbr1);
73 73
74#define MIN_DLL_ON_FREQ 333000000 74#define MIN_DLL_ON_FREQ 333000000
75#define MAX_DLL_OFF_FREQ 125000000 75#define MAX_DLL_OFF_FREQ 125000000
76#define DDR_FREQ_CHANGE_SIZE 0x2000
77 76
78unsigned long ddr3_dll_mx6q[][2] = { 77unsigned long ddr3_dll_mx6q[][2] = {
79 {0x0c, 0x0}, 78 {0x0c, 0x0},
@@ -173,6 +172,7 @@ int update_ddr_freq(int ddr_rate)
173 unsigned int online_cpus = 0; 172 unsigned int online_cpus = 0;
174 int cpu = 0; 173 int cpu = 0;
175 int me; 174 int me;
175 unsigned long ttbr1;
176 176
177 if (!can_change_ddr_freq()) 177 if (!can_change_ddr_freq())
178 return -1; 178 return -1;
@@ -229,15 +229,11 @@ int update_ddr_freq(int ddr_rate)
229 while (cpus_in_wfe != online_cpus) 229 while (cpus_in_wfe != online_cpus)
230 udelay(5); 230 udelay(5);
231 231
232 /* 232 ttbr1 = save_ttbr1();
233 * Flush the TLB, to ensure no TLB maintenance occurs
234 * when DDR is in self-refresh.
235 */
236 local_flush_tlb_all();
237 /* Now we can change the DDR frequency. */ 233 /* Now we can change the DDR frequency. */
238 mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, 234 mx6_change_ddr_freq(ddr_rate, iram_ddr_settings,
239 dll_off, iram_iomux_settings); 235 dll_off, iram_iomux_settings);
240 236 restore_ttbr1(ttbr1);
241 curr_ddr_rate = ddr_rate; 237 curr_ddr_rate = ddr_rate;
242 238
243 /* DDR frequency change is done . */ 239 /* DDR frequency change is done . */
@@ -258,13 +254,10 @@ int update_ddr_freq(int ddr_rate)
258int init_mmdc_ddr3_settings(struct platform_device *busfreq_pdev) 254int init_mmdc_ddr3_settings(struct platform_device *busfreq_pdev)
259{ 255{
260 struct device *dev = &busfreq_pdev->dev; 256 struct device *dev = &busfreq_pdev->dev;
261 struct platform_device *ocram_dev;
262 unsigned int iram_paddr; 257 unsigned int iram_paddr;
263 int i, err; 258 int i, err;
264 u32 cpu; 259 u32 cpu;
265 struct device_node *node; 260 struct device_node *node;
266 struct gen_pool *iram_pool;
267 void *iram_addr;
268 261
269 node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc-combine"); 262 node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc-combine");
270 if (!node) { 263 if (!node) {
@@ -287,22 +280,6 @@ int init_mmdc_ddr3_settings(struct platform_device *busfreq_pdev)
287 iomux_base = of_iomap(node, 0); 280 iomux_base = of_iomap(node, 0);
288 WARN(!iomux_base, "unable to map iomux registers\n"); 281 WARN(!iomux_base, "unable to map iomux registers\n");
289 282
290 node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm");
291 if (!node) {
292 printk(KERN_ERR "failed to find imx6q-ccm device tree data!\n");
293 return -EINVAL;
294 }
295 ccm_base = of_iomap(node, 0);
296 WARN(!ccm_base, "unable to map mmdc registers\n");
297
298 node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
299 if (!node) {
300 printk(KERN_ERR "failed to find imx6q-pl310-cache device tree data!\n");
301 return -EINVAL;
302 }
303 l2_base = of_iomap(node, 0);
304 WARN(!ccm_base, "unable to map mmdc registers\n");
305
306 node = NULL; 283 node = NULL;
307 node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); 284 node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic");
308 if (!node) { 285 if (!node) {
@@ -374,61 +351,11 @@ int init_mmdc_ddr3_settings(struct platform_device *busfreq_pdev)
374 } 351 }
375 irqs_used[cpu] = irq; 352 irqs_used[cpu] = irq;
376 } 353 }
377
378 node = NULL;
379 node = of_find_compatible_node(NULL, NULL, "mmio-sram");
380 if (!node) {
381 dev_err(dev, "%s: failed to find ocram node\n",
382 __func__);
383 return -EINVAL;
384 }
385
386 ocram_dev = of_find_device_by_node(node);
387 if (!ocram_dev) {
388 dev_err(dev, "failed to find ocram device!\n");
389 return -EINVAL;
390 }
391
392 iram_pool = dev_get_gen_pool(&ocram_dev->dev);
393 if (!iram_pool) {
394 dev_err(dev, "iram pool unavailable!\n");
395 return -EINVAL;
396 }
397
398 iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q); 354 iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q);
399 iram_addr = (void *)gen_pool_alloc(iram_pool,
400 (iomux_settings_size * 8) + 8);
401 iram_iomux_settings = iram_addr;
402 if (!iram_iomux_settings) {
403 dev_err(dev, "unable to alloc iram for IOMUX settings!\n");
404 return -ENOMEM;
405 }
406
407 /*
408 * Allocate extra space to store the number of entries in the
409 * ddr_settings plus 4 extra regsiter information that needs
410 * to be passed to the frequency change code.
411 * sizeof(iram_ddr_settings) = sizeof(ddr_settings) +
412 * entries in ddr_settings + 16.
413 * The last 4 enties store the addresses of the registers:
414 * CCM_BASE_ADDR
415 * MMDC_BASE_ADDR
416 * IOMUX_BASE_ADDR
417 * L2X0_BASE_ADDR
418 */
419 iram_addr = (void *)gen_pool_alloc(iram_pool,
420 (ddr_settings_size * 8) + 8 + 32);
421 iram_ddr_settings = iram_addr;
422 if (!iram_ddr_settings) {
423 dev_err(dev, "unable to alloc iram for ddr settings!\n");
424 return -ENOMEM;
425 }
426 355
427 i = ddr_settings_size + 1; 356 iram_iomux_settings = (void *)IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) +
428 iram_ddr_settings[i][0] = (unsigned long)mmdc_base; 357 (DDR3_IOMUX_SETTINGS_ADDR - MX6Q_IRAM_TLB_BASE_ADDR);
429 iram_ddr_settings[i+1][0] = (unsigned long)ccm_base; 358 iram_ddr_settings = iram_iomux_settings + (iomux_settings_size * 8) + 8;
430 iram_ddr_settings[i+2][0] = (unsigned long)iomux_base;
431 iram_ddr_settings[i+3][0] = (unsigned long)l2_base;
432 359
433 if (cpu_is_imx6q()) { 360 if (cpu_is_imx6q()) {
434 /* store the IOMUX settings at boot. */ 361 /* store the IOMUX settings at boot. */
@@ -451,24 +378,13 @@ int init_mmdc_ddr3_settings(struct platform_device *busfreq_pdev)
451 } 378 }
452 } 379 }
453 380
454 ddr_freq_change_iram_base = (void *)gen_pool_alloc(iram_pool, 381 iram_paddr = DDR3_FREQ_CODE_ADDR;
455 DDR_FREQ_CHANGE_SIZE); 382 /* Calculate the virtual address of the code */
456 if (!ddr_freq_change_iram_base) { 383 ddr_freq_change_iram_base =
457 dev_err(dev, "Cannot alloc iram for ddr freq change code!\n"); 384 (void *)IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) +
458 return -ENOMEM; 385 (iram_paddr - MX6Q_IRAM_TLB_BASE_ADDR);
459 }
460
461 iram_paddr = gen_pool_virt_to_phys(iram_pool,
462 (unsigned long)ddr_freq_change_iram_base);
463 /*
464 * Need to remap the area here since we want
465 * the memory region to be executable.
466 */
467 ddr_freq_change_iram_base = __arm_ioremap(iram_paddr,
468 DDR_FREQ_CHANGE_SIZE,
469 MT_MEMORY_NONCACHED);
470 mx6_change_ddr_freq = (void *)fncpy(ddr_freq_change_iram_base, 386 mx6_change_ddr_freq = (void *)fncpy(ddr_freq_change_iram_base,
471 &mx6_ddr3_freq_change, DDR_FREQ_CHANGE_SIZE); 387 &mx6_ddr3_freq_change, DDR3_FREQ_CODE_SIZE);
472 388
473 curr_ddr_rate = ddr_normal_rate; 389 curr_ddr_rate = ddr_normal_rate;
474 390
diff --git a/arch/arm/mach-imx/busfreq_lpddr2.c b/arch/arm/mach-imx/busfreq_lpddr2.c
index a6c4f4e9ae93..ac209e2a3cd0 100644
--- a/arch/arm/mach-imx/busfreq_lpddr2.c
+++ b/arch/arm/mach-imx/busfreq_lpddr2.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. 2 * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
3 */ 3 */
4 4
5/* 5/*
@@ -42,33 +42,27 @@
42 42
43#include "hardware.h" 43#include "hardware.h"
44 44
45/* DDR settings */ 45
46static void __iomem *mmdc_base;
47static void __iomem *anatop_base;
48static void __iomem *ccm_base;
49static void __iomem *l2_base;
50static struct device *busfreq_dev; 46static struct device *busfreq_dev;
51static void *ddr_freq_change_iram_base; 47static void *ddr_freq_change_iram_base;
52static int curr_ddr_rate; 48static int curr_ddr_rate;
53 49
54unsigned long reg_addrs[4]; 50unsigned long ddr_freq_change_iram_paddr;
55 51
56void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode, 52void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode) = NULL;
57 void *iram_addr) = NULL;
58 53
59extern unsigned int ddr_normal_rate; 54extern unsigned int ddr_normal_rate;
60extern int low_bus_freq_mode; 55extern int low_bus_freq_mode;
61extern int ultra_low_bus_freq_mode; 56extern int ultra_low_bus_freq_mode;
62extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode, 57extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode);
63 void *iram_addr);
64
65
66#define LPDDR2_FREQ_CHANGE_SIZE 0x1000
67 58
59extern unsigned long save_ttbr1(void);
60extern void restore_ttbr1(unsigned long ttbr1);
68 61
69/* change the DDR frequency. */ 62/* change the DDR frequency. */
70int update_lpddr2_freq(int ddr_rate) 63int update_lpddr2_freq(int ddr_rate)
71{ 64{
65 unsigned long ttbr1;
72 if (ddr_rate == curr_ddr_rate) 66 if (ddr_rate == curr_ddr_rate)
73 return 0; 67 return 0;
74 68
@@ -78,11 +72,12 @@ int update_lpddr2_freq(int ddr_rate)
78 * Flush the TLB, to ensure no TLB maintenance occurs 72 * Flush the TLB, to ensure no TLB maintenance occurs
79 * when DDR is in self-refresh. 73 * when DDR is in self-refresh.
80 */ 74 */
81 local_flush_tlb_all(); 75 ttbr1 = save_ttbr1();
76
82 /* Now change DDR frequency. */ 77 /* Now change DDR frequency. */
83 mx6_change_lpddr2_freq(ddr_rate, 78 mx6_change_lpddr2_freq(ddr_rate,
84 (low_bus_freq_mode | ultra_low_bus_freq_mode), 79 (low_bus_freq_mode | ultra_low_bus_freq_mode));
85 reg_addrs); 80 restore_ttbr1(ttbr1);
86 81
87 curr_ddr_rate = ddr_rate; 82 curr_ddr_rate = ddr_rate;
88 83
@@ -93,89 +88,16 @@ int update_lpddr2_freq(int ddr_rate)
93 88
94int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev) 89int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev)
95{ 90{
96 struct platform_device *ocram_dev;
97 unsigned int iram_paddr;
98 struct device_node *node;
99 struct gen_pool *iram_pool;
100
101 busfreq_dev = &busfreq_pdev->dev; 91 busfreq_dev = &busfreq_pdev->dev;
102 node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-mmdc"); 92
103 if (!node) { 93 ddr_freq_change_iram_paddr = MX6SL_LPDDR2_FREQ_ADDR;
104 printk(KERN_ERR "failed to find imx6sl-mmdc device tree data!\n"); 94 /* Calculate the virtual address of the code */
105 return -EINVAL; 95 ddr_freq_change_iram_base =
106 } 96 (void *)IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) +
107 mmdc_base = of_iomap(node, 0); 97 (ddr_freq_change_iram_paddr - MX6Q_IRAM_TLB_BASE_ADDR);
108 WARN(!mmdc_base, "unable to map mmdc registers\n"); 98
109
110 node = NULL;
111 node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-ccm");
112 if (!node) {
113 printk(KERN_ERR "failed to find imx6sl-ccm device tree data!\n");
114 return -EINVAL;
115 }
116 ccm_base = of_iomap(node, 0);
117 WARN(!ccm_base, "unable to map ccm registers\n");
118
119 node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
120 if (!node) {
121 printk(KERN_ERR "failed to find imx6sl-pl310-cache device tree data!\n");
122 return -EINVAL;
123 }
124 l2_base = of_iomap(node, 0);
125 WARN(!l2_base, "unable to map PL310 registers\n");
126
127 node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
128 if (!node) {
129 printk(KERN_ERR "failed to find imx6sl-pl310-cache device tree data!\n");
130 return -EINVAL;
131 }
132 anatop_base = of_iomap(node, 0);
133 WARN(!anatop_base, "unable to map anatop registers\n");
134
135 node = NULL;
136 node = of_find_compatible_node(NULL, NULL, "mmio-sram");
137 if (!node) {
138 dev_err(busfreq_dev, "%s: failed to find ocram node\n",
139 __func__);
140 return -EINVAL;
141 }
142
143 ocram_dev = of_find_device_by_node(node);
144 if (!ocram_dev) {
145 dev_err(busfreq_dev, "failed to find ocram device!\n");
146 return -EINVAL;
147 }
148
149 iram_pool = dev_get_gen_pool(&ocram_dev->dev);
150 if (!iram_pool) {
151 dev_err(busfreq_dev, "iram pool unavailable!\n");
152 return -EINVAL;
153 }
154
155 reg_addrs[0] = (unsigned long)anatop_base;
156 reg_addrs[1] = (unsigned long)ccm_base;
157 reg_addrs[2] = (unsigned long)mmdc_base;
158 reg_addrs[3] = (unsigned long)l2_base;
159
160 ddr_freq_change_iram_base = (void *)gen_pool_alloc(iram_pool,
161 LPDDR2_FREQ_CHANGE_SIZE);
162 if (!ddr_freq_change_iram_base) {
163 dev_err(busfreq_dev,
164 "Cannot alloc iram for ddr freq change code!\n");
165 return -ENOMEM;
166 }
167
168 iram_paddr = gen_pool_virt_to_phys(iram_pool,
169 (unsigned long)ddr_freq_change_iram_base);
170 /*
171 * Need to remap the area here since we want
172 * the memory region to be executable.
173 */
174 ddr_freq_change_iram_base = __arm_ioremap(iram_paddr,
175 LPDDR2_FREQ_CHANGE_SIZE,
176 MT_MEMORY_NONCACHED);
177 mx6_change_lpddr2_freq = (void *)fncpy(ddr_freq_change_iram_base, 99 mx6_change_lpddr2_freq = (void *)fncpy(ddr_freq_change_iram_base,
178 &mx6_lpddr2_freq_change, LPDDR2_FREQ_CHANGE_SIZE); 100 &mx6_lpddr2_freq_change, LPDDR2_FREQ_CODE_SIZE);
179 101
180 curr_ddr_rate = ddr_normal_rate; 102 curr_ddr_rate = ddr_normal_rate;
181 103
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
index c542f56efc74..6b98392d10e8 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sl.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. 2 * Copyright (C) 2012-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
@@ -20,36 +20,38 @@
20 20
21#include "common.h" 21#include "common.h"
22#include "cpuidle.h" 22#include "cpuidle.h"
23#include "hardware.h"
23 24
24extern u32 audio_bus_freq_mode; 25extern u32 audio_bus_freq_mode;
25extern u32 ultra_low_bus_freq_mode; 26extern u32 ultra_low_bus_freq_mode;
26extern unsigned long reg_addrs[]; 27extern unsigned long reg_addrs[];
27extern void imx6sl_low_power_wfi(void); 28extern void imx6sl_low_power_wfi(void);
28 29
30extern unsigned long save_ttbr1(void);
31extern void restore_ttbr1(unsigned long ttbr1);
32
29static void __iomem *iomux_base; 33static void __iomem *iomux_base;
30static void *wfi_iram_base; 34static void *wfi_iram_base;
31 35
32void (*imx6sl_wfi_in_iram_fn)(void *wfi_iram_base, 36void (*imx6sl_wfi_in_iram_fn)(void *wfi_iram_base,
33 void *iomux_addr, void *regs_addr, u32 audio_mode) = NULL; 37 void *iomux_addr, u32 audio_mode) = NULL;
34 38
35#define WFI_IN_IRAM_SIZE 0x1000
36 39
37static int imx6sl_enter_wait(struct cpuidle_device *dev, 40static int imx6sl_enter_wait(struct cpuidle_device *dev,
38 struct cpuidle_driver *drv, int index) 41 struct cpuidle_driver *drv, int index)
39{ 42{
40 imx6_set_lpm(WAIT_UNCLOCKED); 43 imx6_set_lpm(WAIT_UNCLOCKED);
41 if (ultra_low_bus_freq_mode || audio_bus_freq_mode) { 44 if (ultra_low_bus_freq_mode || audio_bus_freq_mode) {
42 /* 45 unsigned long ttbr1;
43 * Flush the TLB, to ensure no TLB maintenance occurs
44 * when DDR is in self-refresh.
45 */
46 local_flush_tlb_all();
47 /* 46 /*
48 * Run WFI code from IRAM. 47 * Run WFI code from IRAM.
49 * Drop the DDR freq to 1MHz and AHB to 3MHz 48 * Drop the DDR freq to 1MHz and AHB to 3MHz
50 * Also float DDR IO pads. 49 * Also float DDR IO pads.
51 */ 50 */
52 imx6sl_wfi_in_iram_fn(wfi_iram_base, iomux_base, reg_addrs, audio_bus_freq_mode); 51 ttbr1 = save_ttbr1();
52 imx6sl_wfi_in_iram_fn(wfi_iram_base, iomux_base,
53 audio_bus_freq_mode);
54 restore_ttbr1(ttbr1);
53 } else { 55 } else {
54 imx6sl_set_wait_clk(true); 56 imx6sl_set_wait_clk(true);
55 cpu_do_idle(); 57 cpu_do_idle();
@@ -83,10 +85,8 @@ static struct cpuidle_driver imx6sl_cpuidle_driver = {
83 85
84int __init imx6sl_cpuidle_init(void) 86int __init imx6sl_cpuidle_init(void)
85{ 87{
86 struct platform_device *ocram_dev;
87 unsigned int iram_paddr; 88 unsigned int iram_paddr;
88 struct device_node *node; 89 struct device_node *node;
89 struct gen_pool *iram_pool;
90 90
91 node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-iomuxc"); 91 node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-iomuxc");
92 if (!node) { 92 if (!node) {
@@ -96,50 +96,13 @@ int __init imx6sl_cpuidle_init(void)
96 iomux_base = of_iomap(node, 0); 96 iomux_base = of_iomap(node, 0);
97 WARN(!iomux_base, "unable to map iomux registers\n"); 97 WARN(!iomux_base, "unable to map iomux registers\n");
98 98
99 node = NULL; 99 iram_paddr = MX6SL_WFI_IRAM_ADDR;
100 node = of_find_compatible_node(NULL, NULL, "mmio-sram"); 100 /* Calculate the virtual address of the code */
101 if (!node) { 101 wfi_iram_base = (void *)IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) +
102 pr_err("%s: failed to find ocram node\n", 102 (iram_paddr - MX6Q_IRAM_TLB_BASE_ADDR);
103 __func__);
104 return -EINVAL;
105 }
106
107 ocram_dev = of_find_device_by_node(node);
108 if (!ocram_dev) {
109 pr_err("failed to find ocram device!\n");
110 return -EINVAL;
111 }
112
113 iram_pool = dev_get_gen_pool(&ocram_dev->dev);
114 if (!iram_pool) {
115 pr_err("iram pool unavailable!\n");
116 return -EINVAL;
117 }
118 /*
119 * Allocate IRAM memory when ARM executes WFI in
120 * ultra_low_power_mode.
121 */
122 wfi_iram_base = (void *)gen_pool_alloc(iram_pool,
123 WFI_IN_IRAM_SIZE);
124 if (!wfi_iram_base) {
125 pr_err("Cannot alloc iram for wfi code!\n");
126 return -ENOMEM;
127 }
128
129 iram_paddr = gen_pool_virt_to_phys(iram_pool,
130 (unsigned long)wfi_iram_base);
131 /*
132 * Need to remap the area here since we want
133 * the memory region to be executable.
134 */
135 wfi_iram_base = __arm_ioremap(iram_paddr,
136 WFI_IN_IRAM_SIZE,
137 MT_MEMORY_NONCACHED);
138 if (!wfi_iram_base)
139 pr_err("wfi_ram_base NOT remapped\n");
140 103
141 imx6sl_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base, 104 imx6sl_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base,
142 &imx6sl_low_power_wfi, WFI_IN_IRAM_SIZE); 105 &imx6sl_low_power_wfi, MX6SL_WFI_IRAM_CODE_SIZE);
143 106
144 return cpuidle_register(&imx6sl_cpuidle_driver, NULL); 107 return cpuidle_register(&imx6sl_cpuidle_driver, NULL);
145} 108}
diff --git a/arch/arm/mach-imx/ddr3_freq_imx6.S b/arch/arm/mach-imx/ddr3_freq_imx6.S
index 699f32fbe118..cbba4c2a9322 100644
--- a/arch/arm/mach-imx/ddr3_freq_imx6.S
+++ b/arch/arm/mach-imx/ddr3_freq_imx6.S
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. 2 * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
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 as published by 5 * it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
17 */ 17 */
18 18
19#include <linux/linkage.h> 19#include <linux/linkage.h>
20#include "hardware.h"
20 21
21#define MMDC0_MDPDC 0x4 22#define MMDC0_MDPDC 0x4
22#define MMDC0_MDCF0 0x0c 23#define MMDC0_MDCF0 0x0c
@@ -41,6 +42,8 @@
41 42
42#define L2_CACHE_SYNC 0x730 43#define L2_CACHE_SYNC 0x730
43 44
45.extern iram_tlb_phys_addr
46
44 .align 3 47 .align 3
45 48
46 .macro switch_to_528MHz 49 .macro switch_to_528MHz
@@ -331,56 +334,58 @@ ENTRY(mx6_ddr3_freq_change)
331 stmfd sp!, {r4-r12} 334 stmfd sp!, {r4-r12}
332 335
333 /* 336 /*
334 * r5 -> mmdc_base 337 * r5 -> mmdc_base
335 * r6 -> ccm_base 338 * r6 -> ccm_base
336 * r7 -> iomux_base 339 * r7 -> iomux_base
337 * r12 -> l2_base 340 * r12 -> l2_base
338 */ 341 */
339 mov r4, r0 342 mov r4, r0
340 mov r8, r1 343 mov r8, r1
341 mov r9, r2 344 mov r9, r2
342 mov r11, r3 345 mov r11, r3
343 346
344 /*
345 * Get the addresses of the registers.
346 * They are last few entries in the
347 * ddr_settings parameter.
348 * The first entry contains the count,
349 * and each entry is 2 words.
350 */
351 ldr r0, [r1]
352 add r0, r0, #1
353 lsl r0, r0, #3
354 add r1, r0, r1
355 /* mmdc_base. */
356 ldr r5, [r1]
357 add r1, #8
358 /* ccm_base */
359 ldr r6, [r1]
360 add r1, #8
361 /*iomux_base */
362 ldr r7, [r1]
363 add r1, #8
364 /*l2_base */
365 ldr r12, [r1]
366
367ddr_freq_change: 347ddr_freq_change:
368 /* 348 /*
369 * make sure no TLB miss will occur when 349 * To ensure no page table walks occur in DDR, we
370 * the DDR is in self refresh. invalidate 350 * have a another page table stored in IRAM that only
371 * TLB single entry to ensure that the 351 * contains entries pointing to IRAM, AIPS1 and AIPS2.
372 * address is not already in the TLB. 352 * We need to set the TTBR1 to the new IRAM TLB.
353 * Do the following steps:
354 * 1. Flush the Branch Target Address Cache (BTAC)
355 * 2. Set TTBR1 to point to IRAM page table.
356 * 3. Disable page table walks in TTBR0 (PD0 = 1)
357 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
358 * and 2-4G is translated by TTBR1.
373 */ 359 */
374 360
375 adr r10, ddr_freq_change 361 /* Flush the Branch Target Address Cache (BTAC) */
376 362 ldr r6, =0x0
377 ldr r2, [r6] 363 mcr p15, 0, r6, c7, c1, 6
378 ldr r2, [r5] 364 ldr r6, =iram_tlb_phys_addr
379 ldr r2, [r7] 365 ldr r6, [r6]
380 ldr r2, [r8] 366 dsb
381 ldr r2, [r10] 367 isb
382 ldr r2, [r11] 368 /* Store the IRAM table in TTBR1 */
383 ldr r2, [r12] 369 mcr p15, 0, r6, c2, c0, 1
370
371 /* Read TTBCR and set PD0=1, N = 1 */
372 mrc p15, 0, r6, c2, c0, 2
373 orr r6, r6, #0x11
374 mcr p15, 0, r6, c2, c0, 2
375
376 dsb
377 isb
378
379 /* flush the TLB */
380 ldr r6, =0x0
381 mcr p15, 0, r6, c8, c3, 0
382 dsb
383 isb
384
385 ldr r5, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
386 ldr r6, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR)
387 ldr r7, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR)
388 ldr r12, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR)
384 389
385#ifdef CONFIG_CACHE_L2X0 390#ifdef CONFIG_CACHE_L2X0
386 /* 391 /*
@@ -882,6 +887,22 @@ poll_conreq_clear_2:
882 beq poll_conreq_clear_2 887 beq poll_conreq_clear_2
883 888
884done: 889done:
890 /* Restore the TTBCR */
891 dsb
892 isb
893 /* Read TTBCR and set PD0=0, N = 0 */
894 mrc p15, 0, r6, c2, c0, 2
895 bic r6, r6, #0x11
896 mcr p15, 0, r6, c2, c0, 2
897 dsb
898 isb
899
900 /* flush the TLB */
901 ldr r6, =0x0
902 mcr p15, 0, r6, c8, c3, 0
903 dsb
904 isb
905
885 /* restore registers */ 906 /* restore registers */
886 907
887 ldmfd sp!, {r4-r12} 908 ldmfd sp!, {r4-r12}
diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h
index 2b3516d0d238..89dc771baadf 100644
--- a/arch/arm/mach-imx/hardware.h
+++ b/arch/arm/mach-imx/hardware.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. 2 * Copyright 2004-2014 Freescale Semiconductor, Inc.
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
@@ -94,12 +94,22 @@
94 * ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000 94 * ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000
95 * UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000 95 * UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000
96 */ 96 */
97 #if defined(CONFIG_SOC_IMX6Q) || defined(CONFIG_SOC_IMX6SL)
97#define IMX_IO_P2V(x) ( \ 98#define IMX_IO_P2V(x) ( \
98 (((x) & 0x80000000) >> 7) | \ 99 (((x) & 0x80000000) >> 7) | \
99 (0xf4000000 + \ 100 (0xf4000000 + \
100 (((x) & 0x50000000) >> 6) + \ 101 (((x) & 0x50000000) >> 6) + \
101 (((x) & 0x0b000000) >> 4) + \ 102 (((x) & 0x0b000000) >> 4) + \
103 (((x) & 0x00100000) << 5) + \
102 (((x) & 0x000fffff)))) 104 (((x) & 0x000fffff))))
105#else
106#define IMX_IO_P2V(x) ( \
107 (((x) & 0x80000000) >> 7) | \
108 (0xf4000000 + \
109 (((x) & 0x50000000) >> 6) + \
110 (((x) & 0x0b000000) >> 4) + \
111 (((x) & 0x000fffff))))
112#endif
103 113
104#define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x)) 114#define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x))
105 115
diff --git a/arch/arm/mach-imx/imx6sl_wfi.S b/arch/arm/mach-imx/imx6sl_wfi.S
index 0399e704f6c2..20afe0256f5f 100644
--- a/arch/arm/mach-imx/imx6sl_wfi.S
+++ b/arch/arm/mach-imx/imx6sl_wfi.S
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. 2 * Copyright (C) 2012-2014 Freescale Semiconductor, Inc. All Rights Reserved.
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 as published by 5 * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,9 @@
17 */ 17 */
18 18
19#include <linux/linkage.h> 19#include <linux/linkage.h>
20#define IRAM_WAIT_SIZE (1 << 11) 20#include "hardware.h"
21
22.extern iram_tlb_phys_addr
21 23
22 .macro sl_ddr_io_save 24 .macro sl_ddr_io_save
23 25
@@ -154,8 +156,7 @@ fifo_reset2_wait:
154 * IRQs are already disabled. 156 * IRQs are already disabled.
155 * r0: WFI IRAMcode base address. 157 * r0: WFI IRAMcode base address.
156 * r1: IOMUX base address 158 * r1: IOMUX base address
157 * r2: Base address of CCM, ANATOP and MMDC 159 * r2: 1 if in audio_bus_freq_mode
158 * r3: 1 if in audio_bus_freq_mode
159 */ 160 */
160 .align 3 161 .align 3
161ENTRY(imx6sl_low_power_wfi) 162ENTRY(imx6sl_low_power_wfi)
@@ -164,27 +165,57 @@ ENTRY(imx6sl_low_power_wfi)
164 165
165mx6sl_lpm_wfi: 166mx6sl_lpm_wfi:
166 /* Store audio_bus_freq_mode */ 167 /* Store audio_bus_freq_mode */
167 mov r11, r3 168 mov r11, r2
168 169
169 mov r4,r2
170 /* Get the IRAM data storage address. */ 170 /* Get the IRAM data storage address. */
171 mov r10, r0 171 mov r10, r0
172 mov r9, r0 /* get suspend_iram_base */ 172 mov r9, r0 /* get wfi_iram_base */
173 add r9, r9, #IRAM_WAIT_SIZE 173 add r9, r9, #MX6SL_WFI_IRAM_CODE_SIZE
174 174
175 /* Anatop Base address in r3. */ 175 /*
176 ldr r3, [r4] 176 * To ensure no page table walks occur in DDR, we
177 /* CCM Base Address in r2 */ 177 * have a another page table stored in IRAM that only
178 ldr r2, [r4, #0x4] 178 * contains entries pointing to IRAM, AIPS1 and AIPS2.
179 /* MMDC Base Address in r8 */ 179 * We need to set the TTBR1 to the new IRAM TLB.
180 ldr r8, [r4, #0x8] 180 * Do the following steps:
181 /* L2 Base Address in r7 */ 181 * 1. Flush the Branch Target Address Cache (BTAC)
182 ldr r7, [r4, #0xC] 182 * 2. Set TTBR1 to point to IRAM page table.
183 183 * 3. Disable page table walks in TTBR0 (PD0 = 1)
184 ldr r6, [r8] 184 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
185 ldr r6, [r3] 185 * and 2-4G is translated by TTBR1.
186 ldr r6, [r2] 186 */
187 ldr r6, [r1] 187 /* Flush the BTAC. */
188 ldr r6, =0x0
189 mcr p15, 0, r6, c7, c1, 6
190
191 ldr r6, =iram_tlb_phys_addr
192 ldr r6, [r6]
193 dsb
194 isb
195
196 /* Store the IRAM table in TTBR1 */
197 mcr p15, 0, r6, c2, c0, 1
198
199 /* Read TTBCR and set PD0=1, N = 1 */
200 mrc p15, 0, r6, c2, c0, 2
201 orr r6, r6, #0x11
202 mcr p15, 0, r6, c2, c0, 2
203
204 dsb
205 isb
206
207 /* flush the TLB */
208 ldr r6, =0x0
209 mcr p15, 0, r6, c8, c3, 0
210
211 dsb
212 isb
213
214 ldr r1, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR)
215 ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR)
216 ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR)
217 ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
218 ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR)
188 219
189 /* Store the original ARM PODF. */ 220 /* Store the original ARM PODF. */
190 ldr r0, [r2, #0x10] 221 ldr r0, [r2, #0x10]
@@ -546,7 +577,7 @@ ahb_podf1:
546 577
547 b wfi_restore 578 b wfi_restore
548 579
549 audio_arm_clk_restore: 580audio_arm_clk_restore:
550 /* Move ARM back to PLL2_PFD2_400M */ 581 /* Move ARM back to PLL2_PFD2_400M */
551 ldr r6, [r2, #0xC] 582 ldr r6, [r2, #0xC]
552 orr r6, r6, #0x4 583 orr r6, r6, #0x4
@@ -555,7 +586,7 @@ ahb_podf1:
555wfi_restore: 586wfi_restore:
556 /* get suspend_iram_base */ 587 /* get suspend_iram_base */
557 mov r9, r10 588 mov r9, r10
558 add r9, r9, #IRAM_WAIT_SIZE 589 add r9, r9, #MX6SL_WFI_IRAM_CODE_SIZE
559 590
560 /* Restore the DDR IO before exiting self-refresh. */ 591 /* Restore the DDR IO before exiting self-refresh. */
561 sl_ddr_io_restore 592 sl_ddr_io_restore
@@ -585,6 +616,35 @@ poll_dvfs_clear_1:
585 cmp r6, #0x2000000 616 cmp r6, #0x2000000
586 beq poll_dvfs_clear_1 617 beq poll_dvfs_clear_1
587 618
619 /* Enable Automatic power savings. */
620 ldr r6, [r8, #0x404]
621 bic r6, r6, #0x01
622 str r6, [r8, #0x404]
623
624 /* clear SBS - unblock DDR accesses */
625 ldr r6, [r8, #0x410]
626 bic r6, r6, #0x100
627 str r6, [r8, #0x410]
628
629 /* Restore the TTBCR */
630
631 dsb
632 isb
633 /* Read TTBCR and set PD0=0, N = 0 */
634 mrc p15, 0, r6, c2, c0, 2
635 bic r6, r6, #0x11
636 mcr p15, 0, r6, c2, c0, 2
637
638 dsb
639 isb
640
641 /* flush the TLB */
642 ldr r6, =0x0
643 mcr p15, 0, r6, c8, c3, 0
644
645 dsb
646 isb
647
588 /* 648 /*
589 * Add these nops so that the 649 * Add these nops so that the
590 * prefetcher will not try to get 650 * prefetcher will not try to get
@@ -622,16 +682,6 @@ poll_dvfs_clear_1:
622 nop 682 nop
623 nop 683 nop
624 684
625 /* Enable Automatic power savings. */
626 ldr r6, [r8, #0x404]
627 bic r6, r6, #0x01
628 str r6, [r8, #0x404]
629
630 /* clear SBS - unblock DDR accesses */
631 ldr r6, [r8, #0x410]
632 bic r6, r6, #0x100
633 str r6, [r8, #0x410]
634
635 685
636 pop {r4-r11} 686 pop {r4-r11}
637 687
diff --git a/arch/arm/mach-imx/lpddr2_freq_imx6.S b/arch/arm/mach-imx/lpddr2_freq_imx6.S
index a126f110b0d3..3c1c076112ef 100644
--- a/arch/arm/mach-imx/lpddr2_freq_imx6.S
+++ b/arch/arm/mach-imx/lpddr2_freq_imx6.S
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. 2 * Copyright (C) 2012-2014 Freescale Semiconductor, Inc. All Rights Reserved.
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 as published by 5 * it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
17 */ 17 */
18 18
19#include <linux/linkage.h> 19#include <linux/linkage.h>
20#include "hardware.h"
20 21
21 .macro mx6sl_switch_to_24MHz 22 .macro mx6sl_switch_to_24MHz
22 23
@@ -339,30 +340,55 @@ force_measure1:
339 * IRQs are already disabled. 340 * IRQs are already disabled.
340 * r0 : DDR freq. 341 * r0 : DDR freq.
341 * r1: low_bus_freq_mode flag 342 * r1: low_bus_freq_mode flag
342 * r2: Pointer to array containing addresses of registers.
343 */ 343 */
344 .align 3 344 .align 3
345ENTRY(mx6_lpddr2_freq_change) 345ENTRY(mx6_lpddr2_freq_change)
346 346
347 push {r4-r10} 347 push {r4-r10}
348 348
349 mov r4, r2 349 /*
350 ldr r3, [r4] @ANATOP_BASE_ADDR 350 * To ensure no page table walks occur in DDR, we
351 ldr r2, [r4, #0x4] @CCM_BASE_ADDR 351 * have a another page table stored in IRAM that only
352 ldr r8, [r4, #0x8] @MMDC_P0_BASE_ADDR 352 * contains entries pointing to IRAM, AIPS1 and AIPS2.
353 ldr r7, [r4, #0xC] @L2_BASE_ADDR 353 * We need to set the TTBR1 to the new IRAM TLB.
354 * Do the following steps:
355 * 1. Flush the Branch Target Address Cache (BTAC)
356 * 2. Set TTBR1 to point to IRAM page table.
357 * 3. Disable page table walks in TTBR0 (PD0 = 1)
358 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
359 * and 2-4G is translated by TTBR1.
360 */
354 361
355lpddr2_freq_change: 362 /* Flush the Branch Target Address Cache (BTAC) */
356 adr r9, lpddr2_freq_change 363 ldr r6, =0x0
364 mcr p15, 0, r6, c7, c1, 6
357 365
358 /* Prime all TLB entries. */ 366 ldr r6, =iram_tlb_phys_addr
359 ldr r6, [r9] 367 ldr r6, [r6]
360 ldr r6, [r8] 368 dsb
361 ldr r6, [r3] 369 isb
362 ldr r6, [r2] 370 /* Store the IRAM table in TTBR1 */
371 mcr p15, 0, r6, c2, c0, 1
363 372
364 /* Drain all the L1 buffers. */ 373 /* Read TTBCR and set PD0=1, N = 1 */
365 dsb 374 mrc p15, 0, r6, c2, c0, 2
375 orr r6, r6, #0x11
376 mcr p15, 0, r6, c2, c0, 2
377
378 dsb
379 isb
380
381 /* flush the TLB */
382 ldr r6, =0x0
383 mcr p15, 0, r6, c8, c3, 0
384
385 dsb
386 isb
387
388 ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR)
389 ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR)
390 ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
391 ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR)
366 392
367#ifdef CONFIG_CACHE_L2X0 393#ifdef CONFIG_CACHE_L2X0
368 /* 394 /*
@@ -371,14 +397,13 @@ lpddr2_freq_change:
371 */ 397 */
372 mov r6, #0x0 398 mov r6, #0x0
373 str r6, [r7, #0x730] 399 str r6, [r7, #0x730]
374#endif
375
376 /* 400 /*
377 * The second dsb might be needed to keep cache sync (device write) 401 * The second dsb might be needed to keep cache sync (device write)
378 * ordering with the memory accesses before it. 402 * ordering with the memory accesses before it.
379 */ 403 */
380 dsb 404 dsb
381 isb 405 isb
406#endif
382 407
383 /* Disable Automatic power savings. */ 408 /* Disable Automatic power savings. */
384 ldr r6, [r8, #0x404] 409 ldr r6, [r8, #0x404]
@@ -473,6 +498,53 @@ skip_power_down:
473 bic r6, r6, #0x100 498 bic r6, r6, #0x100
474 str r6, [r8, #0x410] 499 str r6, [r8, #0x410]
475 500
501 /* Restore the TTBCR */
502 dsb
503 isb
504 /* Read TTBCR and set PD0=0, N = 0 */
505 mrc p15, 0, r6, c2, c0, 2
506 bic r6, r6, #0x11
507 mcr p15, 0, r6, c2, c0, 2
508 dsb
509 isb
510
511 /* flush the TLB */
512 ldr r6, =0x0
513 mcr p15, 0, r6, c8, c3, 0
514
515 dsb
516 isb
517
518 nop
519 nop
520 nop
521 nop
522 nop
523
524 nop
525 nop
526 nop
527 nop
528 nop
529
530 nop
531 nop
532 nop
533 nop
534 nop
535
536 nop
537 nop
538 nop
539 nop
540 nop
541
542 nop
543 nop
544 nop
545 nop
546 nop
547
476 pop {r4-r10} 548 pop {r4-r10}
477 549
478 /* Restore registers */ 550 /* Restore registers */
diff --git a/arch/arm/mach-imx/mx6.h b/arch/arm/mach-imx/mx6.h
index 16f7eeac2299..2cf91c7e04aa 100644
--- a/arch/arm/mach-imx/mx6.h
+++ b/arch/arm/mach-imx/mx6.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/*
@@ -14,7 +14,7 @@
14#define MX6Q_IO_P2V(x) IMX_IO_P2V(x) 14#define MX6Q_IO_P2V(x) IMX_IO_P2V(x)
15#define MX6Q_IO_ADDRESS(x) IOMEM(MX6Q_IO_P2V(x)) 15#define MX6Q_IO_ADDRESS(x) IOMEM(MX6Q_IO_P2V(x))
16 16
17#define MX6Q_L2_BASE_ADDR 0x00a02000 17#define MX6Q_L2_BASE_ADDR 0x00a02000
18#define MX6Q_L2_SIZE 0x1000 18#define MX6Q_L2_SIZE 0x1000
19#define MX6Q_IOMUXC_BASE_ADDR 0x020e0000 19#define MX6Q_IOMUXC_BASE_ADDR 0x020e0000
20#define MX6Q_IOMUXC_SIZE 0x4000 20#define MX6Q_IOMUXC_SIZE 0x4000
@@ -26,10 +26,27 @@
26#define MX6Q_ANATOP_SIZE 0x1000 26#define MX6Q_ANATOP_SIZE 0x1000
27#define MX6Q_GPC_BASE_ADDR 0x020dc000 27#define MX6Q_GPC_BASE_ADDR 0x020dc000
28#define MX6Q_GPC_SIZE 0x4000 28#define MX6Q_GPC_SIZE 0x4000
29#define MX6Q_MMDC_P0_BASE_ADDR 0x021b0000 29#define MX6Q_MMDC_P0_BASE_ADDR 0x021b0000
30#define MX6Q_MMDC_P0_SIZE 0x4000 30#define MX6Q_MMDC_P0_SIZE 0x4000
31#define MX6Q_MMDC_P1_BASE_ADDR 0x021b4000 31#define MX6Q_MMDC_P1_BASE_ADDR 0x021b4000
32#define MX6Q_MMDC_P1_SIZE 0x4000 32#define MX6Q_MMDC_P1_SIZE 0x4000
33#define MX6Q_AIPS1_BASE_ADDR 0x02000000
34#define MX6Q_AIPS1_SIZE 0x100000
35#define MX6Q_AIPS2_BASE_ADDR 0x02100000
36#define MX6Q_AIPS2_SIZE 0x100000
37
38#define MX6Q_IRAM_TLB_BASE_ADDR 0x00900000
39#define MX6Q_IRAM_TLB_SIZE 0x100000
40#define TT_ATTRIB_NON_CACHEABLE_1M 0x802
33 41
34#define MX6_SUSPEND_IRAM_SIZE 0x1000 42#define MX6_SUSPEND_IRAM_SIZE 0x1000
43#define LPDDR2_FREQ_CODE_SIZE 0x600
44#define DDR3_FREQ_CODE_SIZE 0xC00
45#define DDR3_IOMUX_SETTINGS_SIZE 0x400
46#define MX6SL_WFI_IRAM_CODE_SIZE 0x600
47#define MX6_SUSPEND_IRAM_ADDR MX6Q_IRAM_TLB_BASE_ADDR
48#define DDR3_FREQ_CODE_ADDR (MX6_SUSPEND_IRAM_ADDR + MX6_SUSPEND_IRAM_SIZE)
49#define DDR3_IOMUX_SETTINGS_ADDR (DDR3_FREQ_CODE_ADDR + DDR3_FREQ_CODE_SIZE)
50#define MX6SL_LPDDR2_FREQ_ADDR (MX6_SUSPEND_IRAM_ADDR + MX6_SUSPEND_IRAM_SIZE)
51#define MX6SL_WFI_IRAM_ADDR (MX6SL_LPDDR2_FREQ_ADDR + LPDDR2_FREQ_CODE_SIZE)
35#endif 52#endif
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 314fd9f38c55..3f7449633c65 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -73,15 +73,37 @@
73#define BM_ROMPATCHENL_0D (0x1 << 0) 73#define BM_ROMPATCHENL_0D (0x1 << 0)
74#define ROM_ADDR_FOR_INTERNAL_RAM_BASE 0x10d7c 74#define ROM_ADDR_FOR_INTERNAL_RAM_BASE 0x10d7c
75 75
76static struct gen_pool *iram_pool; 76unsigned long iram_tlb_base_addr;
77unsigned long iram_tlb_phys_addr;
78
77static void *suspend_iram_base; 79static void *suspend_iram_base;
78static unsigned long iram_size, iram_paddr; 80static unsigned long iram_paddr;
79static int (*suspend_in_iram_fn)(void *iram_vbase, 81static int (*suspend_in_iram_fn)(void *iram_vbase,
80 unsigned long iram_pbase, unsigned int cpu_type); 82 unsigned long iram_pbase, unsigned int cpu_type);
81static unsigned int cpu_type; 83static unsigned int cpu_type;
82static void __iomem *ccm_base; 84static void __iomem *ccm_base;
83struct regmap *romcp; 85struct regmap *romcp;
84 86
87unsigned long save_ttbr1(void)
88{
89 unsigned long lttbr1;
90 asm volatile(
91 ".align 4\n"
92 "mrc p15, 0, %0, c2, c0, 1\n"
93 : "=r" (lttbr1)
94 );
95 return lttbr1;
96}
97
98void restore_ttbr1(unsigned long ttbr1)
99{
100 asm volatile(
101 ".align 4\n"
102 "mcr p15, 0, %0, c2, c0, 1\n"
103 : : "r" (ttbr1)
104 );
105}
106
85void imx6_set_cache_lpm_in_wait(bool enable) 107void imx6_set_cache_lpm_in_wait(bool enable)
86{ 108{
87 if ((cpu_is_imx6q() && imx_get_soc_revision() > 109 if ((cpu_is_imx6q() && imx_get_soc_revision() >
@@ -231,8 +253,11 @@ static int imx6_suspend_finish(unsigned long val)
231 * call low level suspend function in iram, 253 * call low level suspend function in iram,
232 * as we need to float DDR IO. 254 * as we need to float DDR IO.
233 */ 255 */
234 local_flush_tlb_all(); 256 u32 ttbr1;
257
258 ttbr1 = save_ttbr1();
235 suspend_in_iram_fn(suspend_iram_base, iram_paddr, cpu_type); 259 suspend_in_iram_fn(suspend_iram_base, iram_paddr, cpu_type);
260 restore_ttbr1(ttbr1);
236 return 0; 261 return 0;
237} 262}
238 263
@@ -323,11 +348,54 @@ static struct map_desc imx6_pm_io_desc[] __initdata = {
323 imx_map_entry(MX6Q, ANATOP, MT_DEVICE), 348 imx_map_entry(MX6Q, ANATOP, MT_DEVICE),
324 imx_map_entry(MX6Q, GPC, MT_DEVICE), 349 imx_map_entry(MX6Q, GPC, MT_DEVICE),
325 imx_map_entry(MX6Q, L2, MT_DEVICE), 350 imx_map_entry(MX6Q, L2, MT_DEVICE),
351 imx_map_entry(MX6Q, IRAM_TLB, MT_MEMORY_NONCACHED),
326}; 352};
327 353
328void __init imx6_pm_map_io(void) 354void __init imx6_pm_map_io(void)
329{ 355{
356 unsigned long i;
357
330 iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); 358 iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc));
359
360 /*
361 * Allocate IRAM for page tables to be used
362 * when DDR is in self-refresh.
363 */
364 iram_tlb_phys_addr = MX6Q_IRAM_TLB_BASE_ADDR;
365 iram_tlb_base_addr = IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR);
366
367 /* Set all entries to 0. */
368 memset((void *)iram_tlb_base_addr, 0, SZ_16K);
369
370 /*
371 * Make sure the IRAM virtual address has a mapping
372 * in the IRAM page table.
373 */
374 i = (IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) >> 18) / 4;
375 *((unsigned long *)iram_tlb_base_addr + i) =
376 MX6Q_IRAM_TLB_BASE_ADDR | TT_ATTRIB_NON_CACHEABLE_1M;
377 /*
378 * Make sure the AIPS1 virtual address has a mapping
379 * in the IRAM page table.
380 */
381 i = (IMX_IO_P2V(MX6Q_AIPS1_BASE_ADDR) >> 18) / 4;
382 *((unsigned long *)iram_tlb_base_addr + i) =
383 MX6Q_AIPS1_BASE_ADDR | TT_ATTRIB_NON_CACHEABLE_1M;
384 /*
385 * Make sure the AIPS2 virtual address has a mapping
386 * in the IRAM page table.
387 */
388 i = (IMX_IO_P2V(MX6Q_AIPS2_BASE_ADDR) >> 18) / 4;
389 *((unsigned long *)iram_tlb_base_addr + i) =
390 MX6Q_AIPS2_BASE_ADDR | TT_ATTRIB_NON_CACHEABLE_1M;
391 /*
392 * Make sure the AIPS2 virtual address has a mapping
393 * in the IRAM page table.
394 */
395 i = (IMX_IO_P2V(MX6Q_L2_BASE_ADDR) >> 18) / 4;
396 *((unsigned long *)iram_tlb_base_addr + i) =
397 MX6Q_L2_BASE_ADDR | TT_ATTRIB_NON_CACHEABLE_1M;
398
331} 399}
332 400
333static int imx6_pm_valid(suspend_state_t state) 401static int imx6_pm_valid(suspend_state_t state)
@@ -349,46 +417,14 @@ void imx6_pm_set_ccm_base(void __iomem *base)
349 417
350void __init imx6_pm_init(void) 418void __init imx6_pm_init(void)
351{ 419{
352 struct device_node *node;
353 unsigned long iram_base;
354 struct platform_device *pdev;
355
356 if (cpu_is_imx6sx())
357 node = of_find_compatible_node(NULL, NULL, "fsl,lpm-sram");
358 else
359 node = of_find_compatible_node(NULL, NULL, "mmio-sram");
360 if (!node) {
361 pr_err("failed to find ocram node!\n");
362 return;
363 }
364
365 pdev = of_find_device_by_node(node);
366 if (!pdev) {
367 pr_err("failed to find ocram device!\n");
368 return;
369 }
370
371 iram_pool = dev_get_gen_pool(&pdev->dev);
372 if (!iram_pool) {
373 pr_err("iram pool unavailable!\n");
374 return;
375 }
376
377 iram_size = MX6_SUSPEND_IRAM_SIZE;
378
379 iram_base = gen_pool_alloc(iram_pool, iram_size);
380 if (!iram_base) {
381 pr_err("unable to alloc iram!\n");
382 return;
383 }
384
385 iram_paddr = gen_pool_virt_to_phys(iram_pool, iram_base);
386 420
387 suspend_iram_base = __arm_ioremap(iram_paddr, iram_size, 421 iram_paddr = MX6_SUSPEND_IRAM_ADDR;
388 MT_MEMORY_NONCACHED); 422 /* Get the virtual address of the suspend code. */
423 suspend_iram_base = (void *)IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR) +
424 (iram_paddr - MX6Q_IRAM_TLB_BASE_ADDR);
389 425
390 suspend_in_iram_fn = (void *)fncpy(suspend_iram_base, 426 suspend_in_iram_fn = (void *)fncpy(suspend_iram_base,
391 &imx6_suspend, iram_size); 427 &imx6_suspend, MX6_SUSPEND_IRAM_SIZE);
392 428
393 suspend_set_ops(&imx6_pm_ops); 429 suspend_set_ops(&imx6_pm_ops);
394 430
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index 0c3bdfc79c0b..86b3998e002e 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -536,6 +536,41 @@ ddr_io_save_dsm_done:
536 /* need to sync L2 cache before DSM. */ 536 /* need to sync L2 cache before DSM. */
537 sync_l2_cache 537 sync_l2_cache
538 538
539 /*
540 * To ensure no page table walks occur in DDR, we
541 * have a another page table stored in IRAM that only
542 * contains entries pointing to IRAM, AIPS1 and AIPS2.
543 * We need to set the TTBR1 to the new IRAM TLB.
544 * Do the following steps:
545 * 1. Flush the Branch Target Address Cache (BTAC)
546 * 2. Set TTBR1 to point to IRAM page table.
547 * 3. Disable page table walks in TTBR0 (PD0 = 1)
548 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
549 * and 2-4G is translated by TTBR1.
550 */
551 /* Flush the BTAC. */
552 ldr r6, =0x0
553 mcr p15, 0, r6, c7, c1, 6
554
555 ldr r6, =iram_tlb_phys_addr
556 ldr r6, [r6]
557 dsb
558 isb
559
560 /* Store the IRAM table in TTBR1 */
561 mcr p15, 0, r6, c2, c0, 1
562 /* Read TTBCR and set PD0=1, N = 1 */
563 mrc p15, 0, r6, c2, c0, 2
564 orr r6, r6, #0x11
565 mcr p15, 0, r6, c2, c0, 2
566
567 dsb
568 isb
569
570 /* flush the TLB */
571 ldr r6, =0x0
572 mcr p15, 0, r6, c8, c3, 0
573
539 ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) 574 ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
540 /* 575 /*
541 * put DDR explicitly into self-refresh and 576 * put DDR explicitly into self-refresh and
@@ -737,6 +772,21 @@ poll_dvfs_clear_2:
737 ldr r7, [r8, #MX6Q_MMDC_MAPSR] 772 ldr r7, [r8, #MX6Q_MMDC_MAPSR]
738 bic r7, r7, #0x1 773 bic r7, r7, #0x1
739 str r7, [r8, #MX6Q_MMDC_MAPSR] 774 str r7, [r8, #MX6Q_MMDC_MAPSR]
775
776 /* Restore TTBCR */
777 dsb
778 isb
779 /* Read TTBCR and set PD0=0, N = 0 */
780 mrc p15, 0, r6, c2, c0, 2
781 bic r6, r6, #0x11
782 mcr p15, 0, r6, c2, c0, 2
783 dsb
784 isb
785
786 /* flush the TLB */
787 ldr r6, =0x0
788 mcr p15, 0, r6, c8, c3, 0
789
740 /* return to suspend finish */ 790 /* return to suspend finish */
741 mov pc, lr 791 mov pc, lr
742 792