aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>2014-04-03 15:02:21 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:16 -0400
commitc083cade58d12edfc9e1315a0f5e8bca3296850c (patch)
tree812ec17694263c03954b333f3510ff7f724dbb0d
parent6a715373c43f16e48883061049e67919281878d1 (diff)
ENGR00306955-1 ARM:imx6x Ensure that both IRAM and OCRAM_S can be mapped in the IRAM page table
To prevent a page table walk in the DDR, its required that the low power code use a minimal set of page tables that are stored in IRAM. This IRAM page table needs to have a known virtual address so the mapping needs to be created at the beginning of boot using iotable_init(). This patch fixes the following issues: 1. Ensure that OCRAM_S, IRAM, AIPS1 and AIPS2 can all be mapped by the IMX_IO_P2V macro. 2. Ensure Section mapping is used for the required addresses in the IRAM page table. 3. Obtain the address of the IRAM/OCRAM_S to be used by low power code from the device tree. Since the device tree is not setup early in the boot, use the flat device tree apis to get the address. Signed-off-by: Ranjani Vaidyanathan <Ranjani.Vaidyanathan@freescale.com>
-rw-r--r--arch/arm/mach-imx/hardware.h26
-rw-r--r--arch/arm/mach-imx/pm-imx6.c83
2 files changed, 71 insertions, 38 deletions
diff --git a/arch/arm/mach-imx/hardware.h b/arch/arm/mach-imx/hardware.h
index 89dc771baadf..378fa846bf99 100644
--- a/arch/arm/mach-imx/hardware.h
+++ b/arch/arm/mach-imx/hardware.h
@@ -89,27 +89,21 @@
89 * AIPS1 0x53f00000+0x100000 -> 0xf5700000+0x100000 89 * AIPS1 0x53f00000+0x100000 -> 0xf5700000+0x100000
90 * AIPS2 0x63f00000+0x100000 -> 0xf5300000+0x100000 90 * AIPS2 0x63f00000+0x100000 -> 0xf5300000+0x100000
91 * mx6q: 91 * mx6q:
92 * SCU 0x00a00000+0x004000 -> 0xf4000000+0x004000 92 * OCRAMS 0x008f8000+0x004000 -> 0xf48f8000+0x004000
93 * IRAM 0x00900000+0x040000 -> 0xf4900000+0x040000
94 * SCU 0x00a00000+0x004000 -> 0xf4a00000+0x004000
95 * AIPS1 0x02000000+0x100000 -> 0xf4200000+0x100000
96 * AIPS2 0x02100000+0x100000 -> 0xf4300000+0x100000
93 * CCM 0x020c4000+0x004000 -> 0xf42c4000+0x004000 97 * CCM 0x020c4000+0x004000 -> 0xf42c4000+0x004000
94 * ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000 98 * ANATOP 0x020c8000+0x004000 -> 0xf42c8000+0x004000
95 * UART4 0x021f0000+0x004000 -> 0xf42f0000+0x004000 99 * UART4 0x021f0000+0x004000 -> 0xf43f0000+0x004000
96 */ 100 */
97 #if defined(CONFIG_SOC_IMX6Q) || defined(CONFIG_SOC_IMX6SL)
98#define IMX_IO_P2V(x) ( \ 101#define IMX_IO_P2V(x) ( \
99 (((x) & 0x80000000) >> 7) | \
100 (0xf4000000 + \ 102 (0xf4000000 + \
101 (((x) & 0x50000000) >> 6) + \ 103 (((x) & 0x50000000) >> 4) + \
102 (((x) & 0x0b000000) >> 4) + \ 104 (((x) & 0x0a000000) >> 4) + \
103 (((x) & 0x00100000) << 5) + \ 105 (((x) & 0x00ffffff))))
104 (((x) & 0x000fffff)))) 106
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
113 107
114#define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x)) 108#define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x))
115 109
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 50a231fecd36..91c7ec39dc49 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -15,6 +15,7 @@
15#include <linux/io.h> 15#include <linux/io.h>
16#include <linux/of.h> 16#include <linux/of.h>
17#include <linux/of_device.h> 17#include <linux/of_device.h>
18#include <linux/of_fdt.h>
18#include <linux/of_irq.h> 19#include <linux/of_irq.h>
19#include <linux/suspend.h> 20#include <linux/suspend.h>
20#include <linux/genalloc.h> 21#include <linux/genalloc.h>
@@ -265,6 +266,12 @@ static int imx6_pm_enter(suspend_state_t state)
265{ 266{
266 struct regmap *g; 267 struct regmap *g;
267 268
269 if (!iram_tlb_base_addr) {
270 pr_warn("No IRAM/OCRAM memory allocated for suspend/resume code. \
271 Please ensure device tree has an entry for fsl,lpm-sram.\n");
272 return -EINVAL;
273 }
274
268 /* 275 /*
269 * L2 can exit by 'reset' or Inband beacon (from remote EP) 276 * L2 can exit by 'reset' or Inband beacon (from remote EP)
270 * toggling phy_powerdown has same effect as 'inband beacon' 277 * toggling phy_powerdown has same effect as 'inband beacon'
@@ -356,6 +363,36 @@ static struct map_desc iram_tlb_io_desc __initdata = {
356 .type = MT_MEMORY_NONCACHED, 363 .type = MT_MEMORY_NONCACHED,
357}; 364};
358 365
366const static char *low_power_ocram_match[] __initconst = {
367 "fsl,lpm-sram",
368 NULL
369};
370
371static int __init imx6_dt_find_lpsram(unsigned long node,
372 const char *uname, int depth, void *data)
373{
374 unsigned long lpram_addr;
375 __be32 *prop;
376
377 if (of_flat_dt_match(node, low_power_ocram_match)) {
378 prop = of_get_flat_dt_prop(node, "reg", NULL);
379 if (!prop)
380 return -EINVAL;
381
382 lpram_addr = be32_to_cpup(prop);
383
384 /* We need to create a 1M page table entry. */
385 iram_tlb_io_desc.virtual = IMX_IO_P2V(lpram_addr & 0xFFF00000);
386 iram_tlb_io_desc.pfn = __phys_to_pfn(lpram_addr & 0xFFF00000);
387 iram_tlb_phys_addr = lpram_addr;
388 iram_tlb_base_addr = IMX_IO_P2V(lpram_addr);
389
390 iotable_init(&iram_tlb_io_desc, 1);
391 }
392 return 0;
393
394}
395
359void __init imx6_pm_map_io(void) 396void __init imx6_pm_map_io(void)
360{ 397{
361 unsigned long i; 398 unsigned long i;
@@ -363,21 +400,14 @@ void __init imx6_pm_map_io(void)
363 iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); 400 iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc));
364 401
365 /* 402 /*
366 * Allocate IRAM for page tables to be used 403 * Get the address of IRAM or OCRAM to be used by the low
367 * when DDR is in self-refresh. 404 * power code from the device tree.
368 */ 405 */
369 if (cpu_is_imx6sx()) { 406 WARN_ON(of_scan_flat_dt(imx6_dt_find_lpsram, NULL));
370 iram_tlb_io_desc.virtual = IMX_IO_P2V(MX6SX_IRAM_TLB_BASE_ADDR); 407
371 iram_tlb_io_desc.pfn = __phys_to_pfn(MX6SX_IRAM_TLB_BASE_ADDR); 408 /* Return if no IRAM space is allocated for suspend/resume code. */
372 iram_tlb_phys_addr = MX6SX_IRAM_TLB_BASE_ADDR; 409 if (!iram_tlb_base_addr)
373 iram_tlb_base_addr = IMX_IO_P2V(MX6SX_IRAM_TLB_BASE_ADDR); 410 return;
374 } else {
375 iram_tlb_io_desc.virtual = IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR);
376 iram_tlb_io_desc.pfn = __phys_to_pfn(MX6Q_IRAM_TLB_BASE_ADDR);
377 iram_tlb_phys_addr = MX6Q_IRAM_TLB_BASE_ADDR;
378 iram_tlb_base_addr = IMX_IO_P2V(MX6Q_IRAM_TLB_BASE_ADDR);
379 }
380 iotable_init(&iram_tlb_io_desc, 1);
381 411
382 /* Set all entries to 0. */ 412 /* Set all entries to 0. */
383 memset((void *)iram_tlb_base_addr, 0, SZ_16K); 413 memset((void *)iram_tlb_base_addr, 0, SZ_16K);
@@ -385,31 +415,34 @@ void __init imx6_pm_map_io(void)
385 /* 415 /*
386 * Make sure the IRAM virtual address has a mapping 416 * Make sure the IRAM virtual address has a mapping
387 * in the IRAM page table. 417 * in the IRAM page table.
418 * Only use the top 11 bits [31-20] when storing the
419 * physical address in the page table as only these
420 * bits are required for 1M mapping.
388 */ 421 */
389 i = (iram_tlb_base_addr >> 18) / 4; 422 i = ((iram_tlb_base_addr >> 20) << 2) / 4;
390 *((unsigned long *)iram_tlb_base_addr + i) = 423 *((unsigned long *)iram_tlb_base_addr + i) =
391 iram_tlb_phys_addr | TT_ATTRIB_NON_CACHEABLE_1M; 424 (iram_tlb_phys_addr & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
392 /* 425 /*
393 * Make sure the AIPS1 virtual address has a mapping 426 * Make sure the AIPS1 virtual address has a mapping
394 * in the IRAM page table. 427 * in the IRAM page table.
395 */ 428 */
396 i = (IMX_IO_P2V(MX6Q_AIPS1_BASE_ADDR) >> 18) / 4; 429 i = ((IMX_IO_P2V(MX6Q_AIPS1_BASE_ADDR) >> 20) << 2) / 4;
397 *((unsigned long *)iram_tlb_base_addr + i) = 430 *((unsigned long *)iram_tlb_base_addr + i) =
398 MX6Q_AIPS1_BASE_ADDR | TT_ATTRIB_NON_CACHEABLE_1M; 431 (MX6Q_AIPS1_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
399 /* 432 /*
400 * Make sure the AIPS2 virtual address has a mapping 433 * Make sure the AIPS2 virtual address has a mapping
401 * in the IRAM page table. 434 * in the IRAM page table.
402 */ 435 */
403 i = (IMX_IO_P2V(MX6Q_AIPS2_BASE_ADDR) >> 18) / 4; 436 i = ((IMX_IO_P2V(MX6Q_AIPS2_BASE_ADDR) >> 20) << 2) / 4;
404 *((unsigned long *)iram_tlb_base_addr + i) = 437 *((unsigned long *)iram_tlb_base_addr + i) =
405 MX6Q_AIPS2_BASE_ADDR | TT_ATTRIB_NON_CACHEABLE_1M; 438 (MX6Q_AIPS2_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
406 /* 439 /*
407 * Make sure the AIPS2 virtual address has a mapping 440 * Make sure the AIPS2 virtual address has a mapping
408 * in the IRAM page table. 441 * in the IRAM page table.
409 */ 442 */
410 i = (IMX_IO_P2V(MX6Q_L2_BASE_ADDR) >> 18) / 4; 443 i = ((IMX_IO_P2V(MX6Q_L2_BASE_ADDR) >> 20) << 2) / 4;
411 *((unsigned long *)iram_tlb_base_addr + i) = 444 *((unsigned long *)iram_tlb_base_addr + i) =
412 MX6Q_L2_BASE_ADDR | TT_ATTRIB_NON_CACHEABLE_1M; 445 (MX6Q_L2_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M;
413 446
414} 447}
415 448
@@ -432,6 +465,12 @@ void imx6_pm_set_ccm_base(void __iomem *base)
432 465
433void __init imx6_pm_init(void) 466void __init imx6_pm_init(void)
434{ 467{
468 if (!iram_tlb_base_addr) {
469 pr_warn("No IRAM/OCRAM memory allocated for suspend/resume code. \
470Please ensure device tree has an entry fsl,lpm-sram\n");
471 return;
472 }
473
435 iram_paddr = iram_tlb_phys_addr + MX6_SUSPEND_IRAM_ADDR_OFFSET; 474 iram_paddr = iram_tlb_phys_addr + MX6_SUSPEND_IRAM_ADDR_OFFSET;
436 /* Get the virtual address of the suspend code. */ 475 /* Get the virtual address of the suspend code. */
437 suspend_iram_base = (void *)IMX_IO_P2V(iram_tlb_phys_addr) + 476 suspend_iram_base = (void *)IMX_IO_P2V(iram_tlb_phys_addr) +