]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00180882- MX6DL Add bus frequency scaling support.
authorRanjani Vaidyanathan <ra5478@freescale.com>
Thu, 26 Apr 2012 03:31:23 +0000 (22:31 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:30 +0000 (08:34 +0200)
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>
arch/arm/mach-mx6/bus_freq.c
arch/arm/mach-mx6/mx6_ddr_freq.S
arch/arm/mach-mx6/mx6_mmdc.c

index 75b9ebdcc7e3197289031ec96ee82eed8dd1dc9a..b721bc0479f006f873953a91eabfba79966ab1fe 100644 (file)
@@ -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;
 }
index d73394dd3dc2ca8d0e8496e76e165d3b5a05c208..85af2a402e684e26894a9fd4996a7ea5789d6745 100644 (file)
@@ -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
index 2b5ce842489ecbfecf6e3aa2aa3f43bc0c6b5028..2498f01e088945e201eded0a8a00762bf0ea5898 100644 (file)
@@ -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