summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGrace Si <b18730@freescale.com>2014-03-04 11:11:50 +0800
committerNitin Garg <nitin.garg@freescale.com>2014-06-03 23:02:02 -0500
commit87df50c319cc1304493e6cd1257a6dacd3bee256 (patch)
treedc1a68c06b8ef151750af1eaf8372dc92888ce40 /arch
parent6c51fa417a1aaf6a97b0f4ec11aee8a0ad686468 (diff)
ENGR00300417: [MX6SL] Add 100M and 24M MMDC parameters for MX6SL LPDDR2
Use different MMDC parameters for 100M and 24M of i.MX6SL LPDDR2 Signed-off-by: Grace Si <b18730@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-mx6/bus_freq.c30
-rw-r--r--arch/arm/mach-mx6/mx6_mmdc.c240
-rw-r--r--arch/arm/mach-mx6/mx6sl_ddr.S18
-rw-r--r--arch/arm/plat-mxc/include/mach/mx6.h6
4 files changed, 193 insertions, 101 deletions
diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c
index ba2636785232..d0e90bd29963 100644
--- a/arch/arm/mach-mx6/bus_freq.c
+++ b/arch/arm/mach-mx6/bus_freq.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -82,9 +82,6 @@ void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr,\
int audio_mode) = NULL;
extern void mx6sl_wait (int arm_podf, unsigned long wfi_iram_addr);
-void *mx6sl_ddr_freq_base;
-void (*mx6sl_ddr_freq_change_iram)(int ddr_freq, int low_bus_freq_mode) = NULL;
-extern void mx6sl_ddr_iram(int ddr_freq);
extern int init_mmdc_settings(void);
extern struct cpu_op *(*get_cpu_op)(int *op);
@@ -175,8 +172,7 @@ void reduce_bus_freq(void)
clk_round_rate(ahb_clk, LPAPM_CLK / 3));
spin_lock_irqsave(&freq_lock, flags);
- mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK,
- low_bus_freq_mode);
+ update_ddr_freq(DDR_AUDIO_CLK);
spin_unlock_irqrestore(&freq_lock, flags);
if (low_bus_freq_mode) {
@@ -221,8 +217,7 @@ void reduce_bus_freq(void)
spin_lock_irqsave(&freq_lock, flags);
/* Now change DDR freq while running from IRAM. */
- mx6sl_ddr_freq_change_iram(LPAPM_CLK,
- low_bus_freq_mode);
+ update_ddr_freq(LPAPM_CLK);
spin_unlock_irqrestore(&freq_lock, flags);
low_bus_freq_mode = 1;
@@ -333,7 +328,7 @@ int set_high_bus_freq(int high_bus_freq)
spin_lock_irqsave(&freq_lock, flags);
/* Change DDR freq in IRAM. */
- mx6sl_ddr_freq_change_iram(ddr_normal_rate, low_bus_freq_mode);
+ update_ddr_freq(ddr_normal_rate);
spin_unlock_irqrestore(&freq_lock, flags);
/* Set periph_clk to be sourced from pll2_pfd2_400M */
@@ -721,9 +716,8 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler);
register_pm_notifier(&imx_bus_freq_pm_notifier);
- if (!cpu_is_mx6sl())
- init_mmdc_settings();
- else {
+
+ if (cpu_is_mx6sl()) {
unsigned long iram_paddr;
/* Allocate IRAM for WFI code when system is
@@ -738,18 +732,8 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
memcpy(mx6sl_wfi_iram_base, mx6sl_wait, SZ_4K);
mx6sl_wfi_iram = (void *)mx6sl_wfi_iram_base;
- /* Allocate IRAM for WFI code when system is
- *in low freq mode.
- */
- iram_alloc(SZ_4K, &iram_paddr);
- /* Need to remap the area here since we want the memory region
- to be executable. */
- mx6sl_ddr_freq_base = __arm_ioremap(iram_paddr,
- SZ_4K, MT_MEMORY_NONCACHED);
- memcpy(mx6sl_ddr_freq_base, mx6sl_ddr_iram, SZ_4K);
- mx6sl_ddr_freq_change_iram = (void *)mx6sl_ddr_freq_base;
-
}
+ init_mmdc_settings();
return 0;
}
diff --git a/arch/arm/mach-mx6/mx6_mmdc.c b/arch/arm/mach-mx6/mx6_mmdc.c
index f0771b652094..1a8d04e6c9b8 100644
--- a/arch/arm/mach-mx6/mx6_mmdc.c
+++ b/arch/arm/mach-mx6/mx6_mmdc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -51,6 +51,9 @@ void __iomem *gic_cpu_base;
void (*mx6_change_ddr_freq)(u32 freq, void *ddr_settings, bool dll_mode, void* iomux_offsets) = NULL;
+void (*mx6l_lpddr2_change_freq)(u32 freq, int low_bus_freq_mode,
+ void *ddr_settings) = NULL;
+
extern unsigned int ddr_low_rate;
extern unsigned int ddr_med_rate;
extern unsigned int ddr_normal_rate;
@@ -59,6 +62,7 @@ extern int audio_bus_freq_mode;
extern int mmdc_med_rate;
extern void __iomem *ccm_base;
extern void mx6_ddr_freq_change(u32 freq, void *ddr_settings, bool dll_mode, void *iomux_offsets);
+extern void mx6sl_ddr_iram(int ddr_freq, int low_bus_freq_mode, void *ddr_settings);
static void *ddr_freq_change_iram_base;
static int ddr_settings_size;
@@ -66,6 +70,7 @@ static int iomux_settings_size;
static volatile unsigned int cpus_in_wfe;
static volatile bool wait_for_ddr_freq_update;
static int curr_ddr_rate;
+static unsigned int ddr_type;
#define MIN_DLL_ON_FREQ 333000000
#define MAX_DLL_OFF_FREQ 125000000
@@ -134,6 +139,30 @@ unsigned long ddr3_400[][2] = {
{0x4850, 0x472D4833}
};
+
+unsigned long lpddr2_400M_6sl[][2] = {
+ {0x0c, 0x0},
+ {0x10, 0x0},
+ {0x14, 0x0},
+ {0x38, 0x0},
+};
+
+
+unsigned long lpddr2_100M_6sl[][2] = {
+ {0x0c, 0x0C0D2073},
+ {0x10, 0x00040482},
+ {0x14, 0x00000049},
+ {0x38, 0x00060222},
+};
+
+
+unsigned long lpddr2_24M_6sl[][2] = {
+ {0x0c, 0x03032073},
+ {0x10, 0x00200482},
+ {0x14, 0x00000049},
+ {0x38, 0x00040222},
+};
+
unsigned long *irq_used;
unsigned long irqs_used_mx6q[] = {
@@ -192,29 +221,55 @@ int update_ddr_freq(int ddr_rate)
dll_off = true;
iram_ddr_settings[0][0] = ddr_settings_size;
- iram_iomux_settings[0][0] = iomux_settings_size;
- if (ddr_rate == ddr_med_rate && cpu_is_mx6q()) {
- for (i = 0; i < ARRAY_SIZE(ddr3_dll_mx6q); i++) {
- iram_ddr_settings[i + 1][0] =
- normal_mmdc_settings[i][0];
- iram_ddr_settings[i + 1][1] =
- normal_mmdc_settings[i][1];
- }
- for (j = 0, i = ARRAY_SIZE(ddr3_dll_mx6q); i < iram_ddr_settings[0][0]; j++, i++) {
- iram_ddr_settings[i + 1][0] =
- ddr3_400[j][0];
- iram_ddr_settings[i + 1][1] =
- ddr3_400[j][1];
+ if (ddr_type == MX6_DDR3)
+ iram_iomux_settings[0][0] = iomux_settings_size;
+
+ if (cpu_is_mx6sl() && (ddr_type == MX6_LPDDR2)) {
+ if (ddr_rate == ddr_normal_rate) {
+ for (i = 0; i < iram_ddr_settings[0][0]; i++) {
+ iram_ddr_settings[i + 1][0] =
+ normal_mmdc_settings[i][0];
+ iram_ddr_settings[i + 1][1] =
+ normal_mmdc_settings[i][1];
+ }
+ } else if (ddr_rate == ddr_med_rate) {
+ for (i = 0; i < iram_ddr_settings[0][0]; i++) {
+ iram_ddr_settings[i + 1][0] =
+ lpddr2_100M_6sl[i][0];
+ iram_ddr_settings[i + 1][1] =
+ lpddr2_100M_6sl[i][1];
+ }
+ } else {
+ for (i = 0; i < iram_ddr_settings[0][0]; i++) {
+ iram_ddr_settings[i + 1][0] =
+ lpddr2_24M_6sl[i][0];
+ iram_ddr_settings[i + 1][1] =
+ lpddr2_24M_6sl[i][1];
+ }
}
- } else if (ddr_rate == ddr_normal_rate) {
- for (i = 0; i < iram_ddr_settings[0][0]; i++) {
- iram_ddr_settings[i + 1][0] =
- normal_mmdc_settings[i][0];
- iram_ddr_settings[i + 1][1] =
- normal_mmdc_settings[i][1];
+ } else {
+ if (ddr_rate == ddr_med_rate && cpu_is_mx6q()) {
+ for (i = 0; i < ARRAY_SIZE(ddr3_dll_mx6q); i++) {
+ iram_ddr_settings[i + 1][0] =
+ normal_mmdc_settings[i][0];
+ iram_ddr_settings[i + 1][1] =
+ normal_mmdc_settings[i][1];
+ }
+ for (j = 0, i = ARRAY_SIZE(ddr3_dll_mx6q); i < iram_ddr_settings[0][0]; j++, i++) {
+ iram_ddr_settings[i + 1][0] =
+ ddr3_400[j][0];
+ iram_ddr_settings[i + 1][1] =
+ ddr3_400[j][1];
+ }
+ } else if (ddr_rate == ddr_normal_rate) {
+ for (i = 0; i < iram_ddr_settings[0][0]; i++) {
+ iram_ddr_settings[i + 1][0] =
+ normal_mmdc_settings[i][0];
+ iram_ddr_settings[i + 1][1] =
+ normal_mmdc_settings[i][1];
+ }
}
}
-
/* Ensure that all Cores are in WFE. */
local_irq_disable();
@@ -224,17 +279,24 @@ int update_ddr_freq(int ddr_rate)
wait_for_ddr_freq_update = true;
for_each_online_cpu(cpu) {
*((char *)(&online_cpus) + (u8)cpu) = 0xff;
- if (cpu != me) {
- /* Set the interrupt to be pending in the GIC. */
- reg = 1 << (irq_used[cpu] % 32);
- writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + (irq_used[cpu] / 32) * 4);
+ if (!cpu_is_mx6sl()) {
+ if (cpu != me) {
+ /* Set the interrupt to be pending in the GIC. */
+ reg = 1 << (irq_used[cpu] % 32);
+ writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + (irq_used[cpu] / 32) * 4);
+ }
}
}
while (cpus_in_wfe != online_cpus)
udelay(5);
+
+
/* Now we can change the DDR frequency. */
- mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, dll_off, iram_iomux_settings);
+ if (cpu_is_mx6sl())
+ mx6l_lpddr2_change_freq(ddr_rate, low_bus_freq_mode, iram_ddr_settings);
+ else
+ mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, dll_off, iram_iomux_settings);
curr_ddr_rate = ddr_rate;
@@ -261,10 +323,20 @@ int init_mmdc_settings(void)
gic_dist_base = ioremap(IC_DISTRIBUTOR_BASE_ADDR, SZ_16K);
gic_cpu_base = ioremap(IC_INTERFACES_BASE_ADDR, SZ_16K);
- if (cpu_is_mx6q())
- ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6q) + ARRAY_SIZE(ddr3_calibration);
- if (cpu_is_mx6dl())
- ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6dl) + ARRAY_SIZE(ddr3_calibration);
+
+ ddr_type = (__raw_readl(MMDC_MDMISC_OFFSET) & MMDC_MDMISC_DDR_TYPE_MASK) >> MMDC_MDMISC_DDR_TYPE_OFFSET;
+ printk(KERN_NOTICE "DDR type is %s\n", ddr_type == 0 ? "DDR3" : "LPDDR2");
+
+ if (ddr_type == MX6_DDR3) {
+ if (cpu_is_mx6q())
+ ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6q) + ARRAY_SIZE(ddr3_calibration);
+ if (cpu_is_mx6dl())
+ ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6dl) + ARRAY_SIZE(ddr3_calibration);
+ } else {
+ if (cpu_is_mx6sl())
+ ddr_settings_size = ARRAY_SIZE(lpddr2_400M_6sl);
+ }
+
normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL);
if (cpu_is_mx6q()) {
@@ -275,6 +347,10 @@ int init_mmdc_settings(void)
memcpy(normal_mmdc_settings, ddr3_dll_mx6dl, sizeof(ddr3_dll_mx6dl));
memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6dl)), ddr3_calibration, sizeof(ddr3_calibration));
}
+ if (cpu_is_mx6sl()) {
+ if (ddr_type == MX6_LPDDR2)
+ memcpy(normal_mmdc_settings, lpddr2_400M_6sl, sizeof(lpddr2_400M_6sl));
+ }
/* Store the original DDR settings at boot. */
for (i = 0; i < ddr_settings_size; i++) {
@@ -299,66 +375,78 @@ int init_mmdc_settings(void)
return ENOMEM;
}
- iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q);
- /* Store the size of the iomux settings in iRAM also,
- * increase the size by 8 bytes.
- */
- iram_iomux_settings = iram_alloc((iomux_settings_size * 8) + 8, &iram_paddr);
- if (iram_iomux_settings == NULL) {
- printk(KERN_DEBUG
- "%s: failed to allocate iRAM memory for iomuxr settings\n",
- __func__);
- return ENOMEM;
- }
+ if (ddr_type == MX6_DDR3) {
+ iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q);
+ /* Store the size of the iomux settings in iRAM also,
+ * increase the size by 8 bytes.
+ */
+ iram_iomux_settings = iram_alloc((iomux_settings_size * 8) + 8, &iram_paddr);
+ if (iram_iomux_settings == NULL) {
+ printk(KERN_DEBUG
+ "%s: failed to allocate iRAM memory for iomuxr settings\n",
+ __func__);
+ return ENOMEM;
+ }
- /* Store the IOMUX settings at boot. */
- if (cpu_is_mx6q()) {
- for (i = 0; i < iomux_settings_size; i++) {
- iomux_offsets_mx6q[i][1] =
- __raw_readl(iomux_base
- + iomux_offsets_mx6q[i][0]);
- iram_iomux_settings[i+1][0] = iomux_offsets_mx6q[i][0];
- iram_iomux_settings[i+1][1] = iomux_offsets_mx6q[i][1];
+ /* Store the IOMUX settings at boot. */
+ if (cpu_is_mx6q()) {
+ for (i = 0; i < iomux_settings_size; i++) {
+ iomux_offsets_mx6q[i][1] =
+ __raw_readl(iomux_base
+ + iomux_offsets_mx6q[i][0]);
+ iram_iomux_settings[i+1][0] = iomux_offsets_mx6q[i][0];
+ iram_iomux_settings[i+1][1] = iomux_offsets_mx6q[i][1];
+ }
+ irq_used = irqs_used_mx6q;
}
- irq_used = irqs_used_mx6q;
- }
- if (cpu_is_mx6dl()) {
- for (i = 0; i < iomux_settings_size; i++) {
- iomux_offsets_mx6dl[i][1] =
- __raw_readl(iomux_base
- + iomux_offsets_mx6dl[i][0]);
- iram_iomux_settings[i+1][0] = iomux_offsets_mx6dl[i][0];
- iram_iomux_settings[i+1][1] = iomux_offsets_mx6dl[i][1];
+ if (cpu_is_mx6dl()) {
+ for (i = 0; i < iomux_settings_size; i++) {
+ iomux_offsets_mx6dl[i][1] =
+ __raw_readl(iomux_base
+ + iomux_offsets_mx6dl[i][0]);
+ iram_iomux_settings[i+1][0] = iomux_offsets_mx6dl[i][0];
+ iram_iomux_settings[i+1][1] = iomux_offsets_mx6dl[i][1];
+ }
+ irq_used = irqs_used_mx6dl;
}
- irq_used = irqs_used_mx6dl;
}
-
/* Allocate IRAM for the DDR freq change code. */
iram_alloc(SZ_8K, &iram_paddr);
/* Need to remap the area here since we want the memory region
to be executable. */
ddr_freq_change_iram_base = __arm_ioremap(iram_paddr,
SZ_8K, MT_MEMORY_NONCACHED);
- memcpy(ddr_freq_change_iram_base, mx6_ddr_freq_change, SZ_8K);
- mx6_change_ddr_freq = (void *)ddr_freq_change_iram_base;
+
+ if (cpu_is_mx6sl()) {
+ if (ddr_type == MX6_LPDDR2) {
+ memcpy(ddr_freq_change_iram_base, mx6sl_ddr_iram, SZ_8K);
+ mx6l_lpddr2_change_freq = (void *)ddr_freq_change_iram_base;
+ }
+ } else {
+ memcpy(ddr_freq_change_iram_base, mx6_ddr_freq_change, SZ_8K);
+ mx6_change_ddr_freq = (void *)ddr_freq_change_iram_base;
+ }
+
curr_ddr_rate = ddr_normal_rate;
- for_each_online_cpu(cpu) {
- /* Set up a reserved interrupt to get all the active cores into a WFE state
- * before changing the DDR frequency.
- */
- err = request_irq(irq_used[cpu], wait_in_wfe_irq, IRQF_PERCPU, "mmdc_1",
- NULL);
- if (err) {
- printk(KERN_ERR "MMDC: Unable to attach to %ld,err = %d\n", irq_used[cpu], err);
- return err;
- }
- err = irq_set_affinity(irq_used[cpu], cpumask_of(cpu));
- if (err) {
- printk(KERN_ERR "MMDC: unable to set irq affinity irq=%ld,\n", irq_used[cpu]);
- return err;
+ if (!cpu_is_mx6sl()) {
+ for_each_online_cpu(cpu) {
+ /* Set up a reserved interrupt to get all the active cores into a WFE state
+ * before changing the DDR frequency.
+ */
+ err = request_irq(irq_used[cpu], wait_in_wfe_irq, IRQF_PERCPU, "mmdc_1",
+ NULL);
+ if (err) {
+ printk(KERN_ERR "MMDC: Unable to attach to %ld,err = %d\n", irq_used[cpu], err);
+ return err;
+ }
+ err = irq_set_affinity(irq_used[cpu], cpumask_of(cpu));
+ if (err) {
+ printk(KERN_ERR "MMDC: unable to set irq affinity irq=%ld,\n", irq_used[cpu]);
+ return err;
+ }
}
}
return 0;
diff --git a/arch/arm/mach-mx6/mx6sl_ddr.S b/arch/arm/mach-mx6/mx6sl_ddr.S
index 9e83985ed0f8..6f6e1a68bfca 100644
--- a/arch/arm/mach-mx6/mx6sl_ddr.S
+++ b/arch/arm/mach-mx6/mx6sl_ddr.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2012-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -326,12 +326,15 @@ force_measure1:
* IRQs are already disabled.
* r0 : DDR freq.
* r1: low_bus_freq_mode flag
+ * r2: MMDC array
*/
ENTRY(mx6sl_ddr_iram)
push {r4-r10}
mx6sl_ddr_freq_change:
+
+ mov r9, r2 @save MMDC array
ldr r3, =ANATOP_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT
@@ -428,6 +431,19 @@ set_to_24MHz:
mx6sl_switch_to_24MHz
done:
+
+ /* updater MMDC */
+ ldr r6, [r9, #0x0] @size of dll array
+ add r9, r9, #8 @skip first eight bytes in array
+update_mmdc1:
+ ldr r0, [r9, #0x0] @ offset
+ ldr r10, [r9, #0x4] @ value
+ str r10, [r8, r0]
+ add r9, r9, #8
+ sub r6, r6, #1
+ cmp r6, #0
+ bgt update_mmdc1
+
/* clear DVFS - exit from self refresh mode */
ldr r6, [r8, #0x404]
bic r6, r6, #0x200000
diff --git a/arch/arm/plat-mxc/include/mach/mx6.h b/arch/arm/plat-mxc/include/mach/mx6.h
index ba38b8a4181e..6e5c289c8609 100644
--- a/arch/arm/plat-mxc/include/mach/mx6.h
+++ b/arch/arm/plat-mxc/include/mach/mx6.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -575,4 +575,8 @@ extern int mx6dl_revision(void);
extern int mx6sl_revision(void);
#endif
+
+#define MX6_DDR3 (0x0)
+#define MX6_LPDDR2 (0x1)
+
#endif /* __ASM_ARCH_MXC_MX6_H__ */