diff options
author | Grace Si <b18730@freescale.com> | 2014-03-04 11:11:50 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-06-03 23:02:02 -0500 |
commit | 87df50c319cc1304493e6cd1257a6dacd3bee256 (patch) | |
tree | dc1a68c06b8ef151750af1eaf8372dc92888ce40 /arch | |
parent | 6c51fa417a1aaf6a97b0f4ec11aee8a0ad686468 (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.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-mx6/mx6_mmdc.c | 240 | ||||
-rw-r--r-- | arch/arm/mach-mx6/mx6sl_ddr.S | 18 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mx6.h | 6 |
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__ */ |