From 3d6de69eca4d2253359981175dcae3ea52c46391 Mon Sep 17 00:00:00 2001 From: Ranjani Vaidyanathan Date: Fri, 7 Oct 2011 12:35:29 -0500 Subject: [PATCH] ENGR00159641: MX6-Add DVFS-CORE support Add DVFS-CORE support for MX6 quad/dual SOC. Signed-off-by: Ranjani Vaidyanathan --- arch/arm/mach-mx6/Kconfig | 1 + arch/arm/mach-mx6/board-mx6q_sabreauto.c | 44 ++++- arch/arm/mach-mx6/cpu.c | 5 + arch/arm/mach-mx6/cpu_op-mx6.c | 17 +- arch/arm/mach-mx6/devices-imx6q.h | 5 + arch/arm/plat-mxc/Makefile | 1 + arch/arm/plat-mxc/devices/platform-imx_dvfs.c | 13 +- arch/arm/plat-mxc/dvfs_core.c | 178 +++++++++++++----- .../plat-mxc/include/mach/devices-common.h | 1 + arch/arm/plat-mxc/include/mach/mx6.h | 6 +- 10 files changed, 206 insertions(+), 65 deletions(-) diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig index ccd3a3321882..9fddbdf21907 100644 --- a/arch/arm/mach-mx6/Kconfig +++ b/arch/arm/mach-mx6/Kconfig @@ -33,6 +33,7 @@ config MACH_MX6Q_SABREAUTO select IMX_HAVE_PLATFORM_IMX_I2C select IMX_HAVE_PLATFORM_VIV_GPU select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_DVFS select IMX_HAVE_PLATFORM_IMX_ESAI select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL select IMX_HAVE_PLATFORM_FSL_USB2_UDC diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c index 2fc366e9ac1e..1d178512bb47 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabreauto.c +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c @@ -45,14 +45,12 @@ #include #include #include +#include +#include + #include #include -#include -#include -#include -#include -#include -#include +#include #include #include #include @@ -61,8 +59,13 @@ #include #include #include -#include -#include + +#include +#include +#include +#include +#include +#include #include "usb.h" #include "devices-imx6q.h" @@ -784,6 +787,29 @@ static int __init early_use_esai_record(char *p) early_param("esai_record", early_use_esai_record); +static struct mxc_dvfs_platform_data sabreauto_dvfscore_data = { + .reg_id = "cpu_vddgp", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 80, +}; + static int mx6_sabre_set_cpu_voltage(u32 cpu_volt) { return mx6_set_cpu_voltage(cpu_volt); @@ -877,6 +903,8 @@ static void __init mx6_board_init(void) imx6q_add_imx2_wdt(0, NULL); imx6q_add_dma(); imx6q_add_gpmi(&mx6q_gpmi_nfc_platform_data); + + imx6q_add_dvfs_core(&sabreauto_dvfscore_data); } extern void __iomem *twd_base; diff --git a/arch/arm/mach-mx6/cpu.c b/arch/arm/mach-mx6/cpu.c index ddc7b98f9597..46ac7da8cbea 100644 --- a/arch/arm/mach-mx6/cpu.c +++ b/arch/arm/mach-mx6/cpu.c @@ -38,6 +38,8 @@ extern void mx6_wait(void); struct cpu_op *(*get_cpu_op)(int *op); static void __iomem *arm_base = IO_ADDRESS(MX6Q_A9_PLATFRM_BASE); +void __iomem *gpc_base; +void __iomem *ccm_base; int mx6_set_cpu_voltage(u32 cpu_volt) { @@ -104,6 +106,9 @@ static int __init post_cpu_init(void) memcpy((void *)cpaddr, mx6_wait, SZ_4K); mx6_wait_in_iram = (void *)mx6_wait_in_iram_base; + gpc_base = MX6_IO_ADDRESS(GPC_BASE_ADDR); + ccm_base = MX6_IO_ADDRESS(CCM_BASE_ADDR); + return 0; } diff --git a/arch/arm/mach-mx6/cpu_op-mx6.c b/arch/arm/mach-mx6/cpu_op-mx6.c index ae3bff98bdde..51bc917f86cc 100644 --- a/arch/arm/mach-mx6/cpu_op-mx6.c +++ b/arch/arm/mach-mx6/cpu_op-mx6.c @@ -12,10 +12,12 @@ */ #include -#include #include +#include +#include extern struct cpu_op *(*get_cpu_op)(int *op); +extern struct dvfs_op *(*get_dvfs_core_op)(int *wp); extern void (*set_num_cpu_op)(int num); static int num_cpu_op; @@ -51,6 +53,18 @@ static struct cpu_op mx6_cpu_op[] = { .cpu_voltage = 900000,}, }; +static struct dvfs_op dvfs_core_setpoint[] = { + {33, 14, 33, 10, 10, 0x08}, /* 1GHz*/ + {30, 12, 33, 10, 10, 0x08}, /* 800MHz */ + {28, 8, 33, 10, 10, 0x08}, /* 400MHz */ + {20, 0, 33, 20, 10, 0x08} }; /* 167MHz*/ + +static struct dvfs_op *mx6_get_dvfs_core_table(int *wp) +{ + *wp = ARRAY_SIZE(dvfs_core_setpoint); + return dvfs_core_setpoint; +} + struct cpu_op *mx6_get_cpu_op(int *op) { *op = num_cpu_op; @@ -69,5 +83,6 @@ void mx6_cpu_op_init(void) set_num_cpu_op = mx6_set_num_cpu_op; num_cpu_op = ARRAY_SIZE(mx6_cpu_op); + get_dvfs_core_op = mx6_get_dvfs_core_table; } diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h index 2d5069fb41c0..b607758074cd 100644 --- a/arch/arm/mach-mx6/devices-imx6q.h +++ b/arch/arm/mach-mx6/devices-imx6q.h @@ -138,3 +138,8 @@ extern const struct imx_pm_imx_data imx6q_pm_imx_data __initconst; extern const struct imx_imx_asrc_data imx6q_imx_asrc_data[] __initconst; #define imx6q_add_asrc(pdata) \ imx_add_imx_asrc(imx6q_imx_asrc_data, pdata) + +extern const struct imx_dvfs_core_data imx6q_dvfs_core_data __initconst; +#define imx6q_add_dvfs_core(pdata) \ + imx_add_dvfs_core(&imx6q_dvfs_core_data, pdata) + diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 458397cf779f..1ef12bfa8fac 100755 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -28,6 +28,7 @@ endif obj-y += devices/ obj-$(CONFIG_ARCH_MX5) += dvfs_core.o +obj-$(CONFIG_ARCH_MX6) += dvfs_core.o # DVFS-PER support obj-$(CONFIG_MXC_DVFS_PER) += dvfs_per.o diff --git a/arch/arm/plat-mxc/devices/platform-imx_dvfs.c b/arch/arm/plat-mxc/devices/platform-imx_dvfs.c index d291819da798..ae62ff9b88ad 100755 --- a/arch/arm/plat-mxc/devices/platform-imx_dvfs.c +++ b/arch/arm/plat-mxc/devices/platform-imx_dvfs.c @@ -9,7 +9,7 @@ #include #include -#define imx5_dvfs_core_data_entry_single(soc) \ +#define imx_dvfs_core_data_entry_single(soc) \ { \ .iobase = soc ## _DVFSCORE_BASE_ADDR, \ .irq = soc ## _INT_GPC1, \ @@ -17,19 +17,24 @@ #ifdef CONFIG_SOC_IMX50 const struct imx_dvfs_core_data imx50_dvfs_core_data __initconst = - imx5_dvfs_core_data_entry_single(MX50); + imx_dvfs_core_data_entry_single(MX50); #endif /* ifdef CONFIG_SOC_IMX50 */ #ifdef CONFIG_SOC_IMX51 const struct imx_dvfs_core_data imx51_dvfs_core_data __initconst = - imx5_dvfs_core_data_entry_single(MX51); + imx_dvfs_core_data_entry_single(MX51); #endif /* ifdef CONFIG_SOC_IMX51 */ #ifdef CONFIG_SOC_IMX53 const struct imx_dvfs_core_data imx53_dvfs_core_data __initconst = - imx5_dvfs_core_data_entry_single(MX53); + imx_dvfs_core_data_entry_single(MX53); #endif /* ifdef CONFIG_SOC_IMX53 */ +#ifdef CONFIG_SOC_IMX6Q +const struct imx_dvfs_core_data imx6q_dvfs_core_data __initconst = + imx_dvfs_core_data_entry_single(MX6Q); +#endif /* ifdef CONFIG_SOC_IMX6Q */ + struct platform_device *__init imx_add_dvfs_core( const struct imx_dvfs_core_data *data, const struct mxc_dvfs_platform_data *pdata) diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c index 954ca8684090..518d064112fa 100755 --- a/arch/arm/plat-mxc/dvfs_core.c +++ b/arch/arm/plat-mxc/dvfs_core.c @@ -43,6 +43,8 @@ #if defined(CONFIG_CPU_FREQ) #include #endif +#include + #include #include @@ -113,12 +115,28 @@ static struct delayed_work dvfs_core_handler; static struct clk *pll1_sw_clk; static struct clk *cpu_clk; static struct clk *dvfs_clk; -static struct regulator *core_regulator; static int cpu_op_nr; extern struct cpu_op *(*get_cpu_op)(int *op); extern int (*set_cpu_voltage)(u32 cpu_volt); +static inline unsigned long dvfs_cpu_jiffies(unsigned long old, u_int div, u_int mult) +{ +#if BITS_PER_LONG == 32 + + u64 result = ((u64) old) * ((u64) mult); + do_div(result, div); + return (unsigned long) result; + +#elif BITS_PER_LONG == 64 + + unsigned long result = old * ((u64) mult); + result /= div; + return result; + +#endif +} + enum { FSVAI_FREQ_NOCHANGE = 0x0, FSVAI_FREQ_INCREASE, @@ -158,15 +176,15 @@ static void dvfs_load_config(int set_point) __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_COUN); /* Set EMAC value */ - __raw_writel((dvfs_core_setpoint[set_point].emac << - MXC_DVFSEMAC_EMAC_OFFSET), - dvfs_data->membase - + MXC_DVFSCORE_EMAC); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_EMAC); + reg &= ~MXC_DVFSEMAC_EMAC_MASK; + reg |= dvfs_core_setpoint[set_point].emac << MXC_DVFSEMAC_EMAC_OFFSET; + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_EMAC); dvfs_config_setpoint = set_point; } -static int set_cpu_freq(int op) +static int mx5_set_cpu_freq(int op) { int arm_podf; int podf; @@ -357,9 +375,59 @@ static int set_cpu_freq(int op) reg |= en_sw_dvfs; __raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset); } -#if defined(CONFIG_CPU_FREQ) - cpufreq_trig_needed = 1; -#endif + return ret; +} + +static int mx6_set_cpu_freq(int op) +{ + int ret = 0; + int org_cpu_rate; + unsigned long rate = 0; + int gp_volt = cpu_op_tbl[op].cpu_voltage; + + org_cpu_rate = clk_get_rate(cpu_clk); + rate = cpu_op_tbl[op].cpu_rate; + + if (rate == org_cpu_rate) + return ret; + + if (rate > org_cpu_rate) { + /* Increase voltage first. */ + ret = set_cpu_voltage(gp_volt); + if (ret < 0) { + printk(KERN_DEBUG "COULD NOT INCREASE GP VOLTAGE!!!!\n"); + return ret; + } + udelay(dvfs_data->delay_time); + } + ret = clk_set_rate(cpu_clk, rate); + if (ret != 0) { + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + return ret; + } + + if (rate < org_cpu_rate) { + /* Increase voltage first. */ + ret = set_cpu_voltage(gp_volt); + if (ret < 0) { + printk(KERN_DEBUG "COULD NOT INCREASE GP VOLTAGE!!!!\n"); + return ret; + } + } + return ret; +} + + +static int set_cpu_freq(int op) +{ + int ret = 0; + + if (cpu_is_mx6q()) + ret = mx6_set_cpu_freq(op); + else + ret = mx5_set_cpu_freq(op); + + cpufreq_trig_needed = 1; old_op = op; return ret; } @@ -403,7 +471,8 @@ static int start_dvfs(void) /* GPCIRQ=1, select ARM IRQ */ reg |= MXC_GPCCNTR_GPCIRQ_ARM; /* ADU=1, select ARM domain */ - reg |= MXC_GPCCNTR_ADU; + if (!cpu_is_mx6q()) + reg |= MXC_GPCCNTR_ADU; __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); /* Set PREDIV bits */ @@ -417,8 +486,11 @@ static int start_dvfs(void) /* FSVAIM=0 */ reg = (reg & ~MXC_DVFSCNTR_FSVAIM); /* Set MAXF, MINF */ - reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); - reg |= 1 << MXC_DVFSCNTR_MAXF_OFFSET; + if (!cpu_is_mx6q()) { + reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK + | MXC_DVFSCNTR_MINF_MASK)); + reg |= 1 << MXC_DVFSCNTR_MAXF_OFFSET; + } /* Select ARM domain */ reg |= MXC_DVFSCNTR_DVFIS; /* Enable DVFS frequency adjustment interrupt */ @@ -432,9 +504,22 @@ static int start_dvfs(void) __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /* Enable DVFS */ - reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); - reg |= MXC_DVFSCNTR_DVFEN; - __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); + if (cpu_is_mx6q()) { + unsigned long cpu_wfi = 0; + int num_cpus = num_possible_cpus(); + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_EMAC); + /* Need to enable DVFS tracking for each core that is active */ + do { + if (cpu_active(num_cpus)) + set_bit(num_cpus, &cpu_wfi); + } while (num_cpus--); + reg |= cpu_wfi << 9; + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_EMAC); + } else { + reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); + reg |= MXC_DVFSCNTR_DVFEN; + __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); + } dvfs_core_is_active = 1; @@ -496,6 +581,7 @@ static void dvfs_core_work_handler(struct work_struct *work) int ret = 0; int low_freq_bus_ready = 0; int bus_incr = 0, cpu_dcr = 0; + int cpu; low_freq_bus_ready = low_freq_bus_used(); @@ -511,7 +597,7 @@ static void dvfs_core_work_handler(struct work_struct *work) /* If FSVAI indicate freq down, check arm-clk is not in lowest frequency*/ if (fsvai == FSVAI_FREQ_DECREASE) { - if (curr_cpu == cpu_op_tbl[cpu_op_nr - 1].cpu_rate) { + if (curr_cpu <= cpu_op_tbl[cpu_op_nr - 1].cpu_rate) { minf = 1; if (low_bus_freq_mode) goto END; @@ -566,7 +652,17 @@ static void dvfs_core_work_handler(struct work_struct *work) bus_incr = 0; } -END: /* Set MAXF, MINF */ +END: + if (cpufreq_trig_needed == 1) { + /*Fix loops-per-jiffy */ + cpufreq_trig_needed = 0; + for_each_online_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + dvfs_cpu_jiffies(per_cpu(cpu_data, cpu).loops_per_jiffy, + curr_cpu / 1000, clk_get_rate(cpu_clk) / 1000); + } + + /* Set MAXF, MINF */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); reg |= maxf << MXC_DVFSCNTR_MAXF_OFFSET; @@ -585,19 +681,6 @@ END: /* Set MAXF, MINF */ reg &= ~MXC_GPCCNTR_GPCIRQM; __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); -#if defined(CONFIG_CPU_FREQ) - if (cpufreq_trig_needed == 1) { - struct cpufreq_freqs freqs; - unsigned int target_freq; - cpufreq_trig_needed = 0; - freqs.old = curr_cpu/1000; - freqs.new = clk_get_rate(cpu_clk) / 1000; - freqs.cpu = 0; - freqs.flags = 0; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } -#endif } @@ -609,6 +692,7 @@ void stop_dvfs(void) u32 reg = 0; unsigned long flags; u32 curr_cpu; + int cpu; if (dvfs_core_is_active) { @@ -627,21 +711,13 @@ void stop_dvfs(void) curr_cpu = clk_get_rate(cpu_clk); if (curr_cpu != cpu_op_tbl[curr_op].cpu_rate) { set_cpu_freq(curr_op); -#if defined(CONFIG_CPU_FREQ) - if (cpufreq_trig_needed == 1) { - struct cpufreq_freqs freqs; - unsigned int target_freq; - cpufreq_trig_needed = 0; - freqs.old = curr_cpu/1000; - freqs.new = clk_get_rate(cpu_clk) / 1000; - freqs.cpu = 0; - freqs.flags = 0; - cpufreq_notify_transition(&freqs, - CPUFREQ_PRECHANGE); - cpufreq_notify_transition(&freqs, - CPUFREQ_POSTCHANGE); - } -#endif + + /*Fix loops-per-jiffy */ + for_each_online_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + dvfs_cpu_jiffies(per_cpu(cpu_data, cpu).loops_per_jiffy, + curr_cpu/1000, clk_get_rate(cpu_clk) / 1000); + } spin_lock_irqsave(&mxc_dvfs_core_lock, flags); @@ -841,13 +917,13 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) printk(KERN_ERR "%s: failed to get cpu clock\n", __func__); return PTR_ERR(cpu_clk); } - - dvfs_clk = clk_get(NULL, dvfs_data->clk2_id); - if (IS_ERR(dvfs_clk)) { - printk(KERN_ERR "%s: failed to get dvfs clock\n", __func__); - return PTR_ERR(dvfs_clk); + if (!cpu_is_mx6q()) { + dvfs_clk = clk_get(NULL, dvfs_data->clk2_id); + if (IS_ERR(dvfs_clk)) { + printk(KERN_ERR "%s: failed to get dvfs clock\n", __func__); + return PTR_ERR(dvfs_clk); + } } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { err = -ENODEV; diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index 59ea7f8390af..693e14c3a916 100755 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -369,6 +369,7 @@ struct imx_dvfs_core_data { struct platform_device *__init imx_add_dvfs_core( const struct imx_dvfs_core_data *data, const struct mxc_dvfs_platform_data *pdata); + struct platform_device *__init imx_add_busfreq(void); #include diff --git a/arch/arm/plat-mxc/include/mach/mx6.h b/arch/arm/plat-mxc/include/mach/mx6.h index b3042cb22984..cead192fc94a 100644 --- a/arch/arm/plat-mxc/include/mach/mx6.h +++ b/arch/arm/plat-mxc/include/mach/mx6.h @@ -182,6 +182,7 @@ #define DCIC1_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x64000) #define DCIC2_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x68000) #define MX6Q_SDMA_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x6C000) +#define MX6Q_DVFSCORE_BASE_ADDR (GPC_BASE_ADDR + 0x180) /* ATZ#2- On Platform */ #define AIPS2_ON_BASE_ADDR (ATZ2_BASE_ADDR + 0x7C000) @@ -255,6 +256,9 @@ #define AIPS2_SIZE SZ_1M #define ARM_PERIPHBASE_SIZE (SZ_8K + SZ_4K) +/* GPC offsets */ +#define MXC_GPC_CNTR_OFFSET 0x0 + #define MX6_IO_ADDRESS(x) (void __force __iomem *)((x) + PERIPBASE_VIRT) /*! @@ -363,7 +367,7 @@ #define MXC_INT_PWM4 118 #define MXC_INT_CCM_INT1_NUM 119 #define MXC_INT_CCM_INT2_NUM 120 -#define MXC_INT_GPC_INT1_NUM 121 +#define MX6Q_INT_GPC1 121 #define MXC_INT_GPC_INT2_NUM 122 #define MXC_INT_SRC 123 #define MXC_INT_CHEETAH_L2 124 -- 2.39.5