summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2012-04-25 22:31:23 -0500
committerRanjani Vaidyanathan <ra5478@freescale.com>2012-04-26 11:08:49 -0500
commit4800abecba6e82a49462bc962ad647450f006175 (patch)
tree068806d22a565a3231c08404d7d57ec75b5b104d
parentbc7144148d171d00f406ccc98b8ee12bcda83f84 (diff)
ENGR00180882- MX6DL Add bus frequency scaling support.
Added support for changing DDR frequency on MX6DL. During system IDLE, DDR freq can drop down to 24MHz if none of the devices that need high AHB frequency are active. Changed the DDR code to handle both MX6Q and MX6DL DDR and IOMUX settings. Fixed bug associated incorrect IRAM memory allocation used to store DDR and IOMUX data. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
-rw-r--r--arch/arm/mach-mx6/bus_freq.c22
-rw-r--r--arch/arm/mach-mx6/mx6_ddr_freq.S73
-rw-r--r--arch/arm/mach-mx6/mx6_mmdc.c84
3 files changed, 129 insertions, 50 deletions
diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c
index 75b9ebdcc7e3..b721bc0479f0 100644
--- a/arch/arm/mach-mx6/bus_freq.c
+++ b/arch/arm/mach-mx6/bus_freq.c
@@ -111,6 +111,7 @@ static void reduce_bus_freq_handler(struct work_struct *work)
mutex_unlock(&bus_freq_mutex);
return;
}
+
if (audio_bus_freq_mode && lp_audio_freq) {
mutex_unlock(&bus_freq_mutex);
return;
@@ -131,20 +132,21 @@ static void reduce_bus_freq_handler(struct work_struct *work)
low_bus_freq_mode = 1;
audio_bus_freq_mode = 0;
}
+
if (med_bus_freq_mode)
clk_disable(pll2_400);
high_bus_freq_mode = 0;
med_bus_freq_mode = 0;
- /* Power gate the PU LDO. */
- org_ldo = reg = __raw_readl(ANADIG_REG_CORE);
- reg &= ~(ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET);
- __raw_writel(reg, ANADIG_REG_CORE);
-
- mutex_unlock(&bus_freq_mutex);
+ if (cpu_is_mx6q()) {
+ /* Power gate the PU LDO. */
+ org_ldo = reg = __raw_readl(ANADIG_REG_CORE);
+ reg &= ~(ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET);
+ __raw_writel(reg, ANADIG_REG_CORE);
+ }
clk_disable(pll3);
-
+ mutex_unlock(&bus_freq_mutex);
}
@@ -195,7 +197,7 @@ int set_high_bus_freq(int high_bus_freq)
clk_enable(pll3);
/* Enable the PU LDO */
- if (low_bus_freq_mode)
+ if (cpu_is_mx6q() && low_bus_freq_mode)
__raw_writel(org_ldo, ANADIG_REG_CORE);
if (high_bus_freq) {
@@ -215,8 +217,10 @@ int set_high_bus_freq(int high_bus_freq)
low_bus_freq_mode = 0;
audio_bus_freq_mode = 0;
- mutex_unlock(&bus_freq_mutex);
+ low_bus_freq_mode = 0;
+
clk_disable(pll3);
+ mutex_unlock(&bus_freq_mutex);
return 0;
}
diff --git a/arch/arm/mach-mx6/mx6_ddr_freq.S b/arch/arm/mach-mx6/mx6_ddr_freq.S
index d73394dd3dc2..85af2a402e68 100644
--- a/arch/arm/mach-mx6/mx6_ddr_freq.S
+++ b/arch/arm/mach-mx6/mx6_ddr_freq.S
@@ -348,7 +348,7 @@ ddr_freq_change:
/* set CON_REG */
ldr r0, =0x8000
- str r0, [r5, #0x1C]
+ str r0, [r5, #0x1C]
poll_conreq_set_1:
ldr r0, [r5, #0x1C]
and r0, r0, #0x4000
@@ -587,7 +587,7 @@ poll_conreq_clear_1:
dll_on_mode:
/* assert DVFS - enter self refresh mode */
ldr r0, [r5, #0x404]
- orr r0, r0, #0x200000
+ orr r0, r0, #0x200000
str r0, [r5, #0x404]
/* de-assert CON_REQ */
@@ -632,7 +632,7 @@ poll_dvfs_clear_2:
/* if DLL is currently off, turn it back on */
cmp r9, #0
- beq update_calibration
+ beq update_calibration_only
ldr r0, =0xa5390003
str r0, [r5, #0x800]
@@ -697,16 +697,17 @@ update_iomux1:
@//setmem /32 0x021b0014 = 0x01ff00db @// MMDC0_MDCFG2 - tRRD - 4ck; tWTR - 4ck; tRTP - 4ck; tDLLK - 512ck
@//setmem /32 0x021b0018 = 0x00081740 @// MMDC0_MDMISC, RALAT=0x5 (original value)
*/
+ ldr r9, [r8] @size of array
+ add r8, r8, #8 @skip first eight bytes in array
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
- ldr r0, [r5, #0x0C]
- bic r0, r0, #0xf
- orr r0, r0, #0x5
- str r0, [r5, #0x0C]
-
- ldr r0, [r5, #0x10]
- bic r0, r0, #0x7
- orr r0, r0, #0x4
- str r0, [r5, #0x10]
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
/* update MISC register: WALAT, RALAT */
ldr r0, =0x00081740
@@ -762,11 +763,17 @@ cont8:
@//setmem /32 0x021b001c = 0x04088032
@//setmem /32 0x021b001c = 0x0408803a
*/
- ldr r0, =0x04088032
- str r0, [r5, #0x1C]
+ /* MR2 - CS0 */
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
- ldr r0, =0x0408803a
- str r0, [r5, #0x1C]
+ /*MR2 - CS1 */
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
ldr r0, =0x00428031
str r0, [r5, #0x1C]
@@ -778,11 +785,17 @@ cont8:
@// setmem /32 0x021b001c = 0x08408030
@// setmem /32 0x021b001c = 0x08408038
*/
- ldr r0, =0x08408030
- str r0, [r5, #0x1C]
+ /* MR1 - CS0 */
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
- ldr r0, =0x08408038
- str r0, [r5, #0x1C]
+ /*MR1 - CS1 */
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
/* issue a zq command
@// setmem /32 0x021b001c = 0x04000040
@@ -798,8 +811,11 @@ cont8:
@//setmem /32 0x021b0818 = 0x00022225 @// DDR_PHY_P0_MPODTCTRL
@//setmem /32 0x021b4818 = 0x00022225 @// DDR_PHY_P1_MPODTCTRL
*/
- ldr r0, =0x00022225
- str r0, [r5, #0x818]
+ ldr r0, [r8, #0x0] @ offset
+ ldr r3, [r8, #0x4] @ value
+ str r3, [r5, r0]
+ add r8, r8, #8
+
ldr r2, =0x4818
str r0, [r5, r2]
@@ -827,10 +843,19 @@ cont15:
orr r0, r0, #0x5500
str r0, [r5, #0x4]
+ b update_calibration
+
+update_calibration_only:
+ ldr r1, [r8] @ size of array
+ sub r1, r1, #7 @ first 7 entries are not related to calibration
+ add r8, r8, #64 @ Skip the first 7 entries that are needed only when DLL was OFF + count entry.
+ b update_calib
+
update_calibration:
/* Write the new calibration values. */
- ldr r1, [r8] @size of array
- add r8, r8, #8 @skip first eight bytes in array
+ mov r1, r9 @ size of array
+ sub r1, r1, #7 @ first 7 entries are not related to calibration
+
update_calib:
ldr r0, [r8, #0x0] @ offset
ldr r3, [r8, #0x4] @ value
diff --git a/arch/arm/mach-mx6/mx6_mmdc.c b/arch/arm/mach-mx6/mx6_mmdc.c
index 2b5ce842489e..2498f01e0889 100644
--- a/arch/arm/mach-mx6/mx6_mmdc.c
+++ b/arch/arm/mach-mx6/mx6_mmdc.c
@@ -64,12 +64,22 @@ static int ddr_settings_size;
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;
#define MIN_DLL_ON_FREQ 333000000
#define MAX_DLL_OFF_FREQ 125000000
-unsigned long ddr3_mmdc_regs_offsets[][2] = {
+unsigned long ddr3_dll_mx6q[][2] = {
+ {0x0c, 0x0},
+ {0x10, 0x0},
+ {0x1C, 0x04088032},
+ {0x1C, 0x0408803a},
+ {0x1C, 0x08408030},
+ {0x1C, 0x08408038},
+ {0x818, 0x0},
+};
+
+unsigned long ddr3_calibration[][2] = {
{0x83c, 0x0},
{0x840, 0x0},
{0x483c, 0x0},
@@ -80,6 +90,16 @@ unsigned long ddr3_mmdc_regs_offsets[][2] = {
{0x4850, 0x0},
};
+unsigned long ddr3_dll_mx6dl[][2] = {
+ {0x0c, 0x0},
+ {0x10, 0x0},
+ {0x1C, 0x04008032},
+ {0x1C, 0x0400803a},
+ {0x1C, 0x07208030},
+ {0x1C, 0x07208038},
+ {0x818, 0x0},
+};
+
unsigned long iomux_offsets_mx6q[][2] = {
{0x5A8, 0x0},
{0x5B0, 0x0},
@@ -90,6 +110,7 @@ unsigned long iomux_offsets_mx6q[][2] = {
{0x5B8, 0x0},
{0x5C0, 0x0},
};
+
unsigned long iomux_offsets_mx6dl[][2] = {
{0x4BC, 0x0},
{0x4C0, 0x0},
@@ -146,13 +167,14 @@ irqreturn_t wait_in_wfe_irq(int irq, void *dev_id)
wfe();
*((char *)(&cpus_in_wfe) + (u8)me) = 0;
+
return IRQ_HANDLED;
}
/* Change the DDR frequency. */
int update_ddr_freq(int ddr_rate)
{
- int i;
+ int i, j;
unsigned int reg;
bool dll_off = false;
unsigned int online_cpus = 0;
@@ -162,17 +184,26 @@ int update_ddr_freq(int ddr_rate)
if (!can_change_ddr_freq())
return -1;
+ if (ddr_rate == curr_ddr_rate)
+ return 0;
+
if (low_bus_freq_mode)
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) {
- for (i = 0; i < iram_ddr_settings[0][0]; i++) {
+ 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] =
- ddr3_400[i][0];
+ normal_mmdc_settings[i][0];
iram_ddr_settings[i + 1][1] =
- ddr3_400[i][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++) {
@@ -190,7 +221,6 @@ int update_ddr_freq(int ddr_rate)
*((char *)(&cpus_in_wfe) + (u8)me) = 0xff;
wait_for_ddr_freq_update = true;
-
for_each_online_cpu(cpu) {
*((char *)(&online_cpus) + (u8)cpu) = 0xff;
if (cpu != me) {
@@ -206,6 +236,8 @@ int update_ddr_freq(int ddr_rate)
/* Now we can change the DDR frequency. */
mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, dll_off, iram_iomux_settings);
+ curr_ddr_rate = ddr_rate;
+
/* DDR frequency change is done . */
wait_for_ddr_freq_update = false;
@@ -229,19 +261,37 @@ 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);
- normal_mmdc_settings = ddr3_mmdc_regs_offsets;
- ddr_settings_size = ARRAY_SIZE(ddr3_mmdc_regs_offsets);
+ 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);
+
+ normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL);
+ if (cpu_is_mx6q()) {
+ memcpy(normal_mmdc_settings, ddr3_dll_mx6q, sizeof(ddr3_dll_mx6q));
+ memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6q)), ddr3_calibration, sizeof(ddr3_calibration));
+ }
+ if (cpu_is_mx6dl()) {
+ 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));
+ }
/* Store the original DDR settings at boot. */
for (i = 0; i < ddr_settings_size; i++) {
- normal_mmdc_settings[i][1] =
- __raw_readl(mmdc_base
- + normal_mmdc_settings[i][0]);
+ /*Writes via command mode register cannot be read back.
+ * Hence hardcode them in the initial static array.
+ * This may require modification on a per customer basis.
+ */
+ if (normal_mmdc_settings[i][0] != 0x1C)
+ normal_mmdc_settings[i][1] =
+ __raw_readl(mmdc_base
+ + normal_mmdc_settings[i][0]);
}
+
/* Store the size of the array in iRAM also,
* increase the size by 8 bytes.
*/
- iram_ddr_settings = iram_alloc(ddr_settings_size + 8, &iram_paddr);
+ iram_ddr_settings = iram_alloc((ddr_settings_size * 8) + 8, &iram_paddr);
if (iram_ddr_settings == NULL) {
printk(KERN_DEBUG
"%s: failed to allocate iRAM memory for ddr settings\n",
@@ -249,10 +299,11 @@ 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, &iram_paddr);
+ 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",
@@ -262,7 +313,6 @@ int init_mmdc_settings(void)
/* Store the IOMUX settings at boot. */
if (cpu_is_mx6q()) {
- iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q);
for (i = 0; i < iomux_settings_size; i++) {
iomux_offsets_mx6q[i][1] =
__raw_readl(iomux_base
@@ -272,8 +322,8 @@ int init_mmdc_settings(void)
}
irq_used = irqs_used_mx6q;
}
+
if (cpu_is_mx6dl()) {
- iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6dl);
for (i = 0; i < iomux_settings_size; i++) {
iomux_offsets_mx6dl[i][1] =
__raw_readl(iomux_base