diff options
-rw-r--r-- | arch/arm/mach-imx/anatop.c | 57 | ||||
-rw-r--r-- | arch/arm/mach-imx/clk-imx6q.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-imx/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/gpc.c | 60 |
4 files changed, 124 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index 0cfa07dd9aa4..f7efabee5ccb 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c @@ -9,6 +9,7 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include <linux/of.h> @@ -23,6 +24,7 @@ #define ANADIG_REG_2P5 0x130 #define ANADIG_REG_CORE 0x140 #define ANADIG_ANA_MISC0 0x150 +#define ANADIG_ANA_MISC2 0x170 #define ANADIG_USB1_CHRG_DETECT 0x1b0 #define ANADIG_USB2_CHRG_DETECT 0x210 #define ANADIG_DIGPROG 0x260 @@ -33,8 +35,55 @@ #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000 #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000 +#define ANADIG_ANA_MISC2_REG1_STEP_OFFSET 26 +#define ANADIG_ANA_MISC2_REG_STEP_MASK 0x3 +#define ANADIG_REG_CORE_REG_MASK 0x1f +#define ANADIG_REG_CORE_REG2_OFFSET 18 /* VDDSOC */ +#define ANADIG_REG_CORE_REG1_OFFSET 9 /* VDDPU */ + +#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ +#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* base on 24M OSC */ + static struct regmap *anatop; +static void imx_anatop_pu_enable(bool enable) +{ + u32 val, vddsoc; + + regmap_read(anatop, ANADIG_REG_CORE, &val); + if (enable) { + /* VDDPU track with VDDSOC if enable */ + val &= ~(ANADIG_REG_CORE_REG_MASK << + ANADIG_REG_CORE_REG1_OFFSET); + vddsoc = val & (ANADIG_REG_CORE_REG_MASK << + ANADIG_REG_CORE_REG2_OFFSET); + val |= vddsoc >> (ANADIG_REG_CORE_REG2_OFFSET - + ANADIG_REG_CORE_REG1_OFFSET); + } else + /* power off pu */ + val &= ~(ANADIG_REG_CORE_REG_MASK << + ANADIG_REG_CORE_REG1_OFFSET); + regmap_write(anatop, ANADIG_REG_CORE, val); + + if (enable) { + /* + * the delay time for LDO ramp up time is + * based on the register setting, we need + * to calculate how many steps LDO need to + * ramp up, and how much delay needed. (us) + */ + static u32 new_vol, delay_u; + regmap_read(anatop, ANADIG_ANA_MISC2, &val); + val = (val >> ANADIG_ANA_MISC2_REG1_STEP_OFFSET) & + ANADIG_ANA_MISC2_REG_STEP_MASK; + new_vol = (vddsoc >> ANADIG_REG_CORE_REG2_OFFSET) & + ANADIG_REG_CORE_REG_MASK; + delay_u = new_vol * ((LDO_RAMP_UP_UNIT_IN_CYCLES << + val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1); + udelay(delay_u); + } +} + static void imx_anatop_enable_weak2p5(bool enable) { u32 reg, val; @@ -100,4 +149,12 @@ void __init imx_anatop_init(void) pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__); return; } + + /* + * PU is turned off in uboot, so we need to turn it on here + * to avoid kernel hang during GPU init, will remove + * this code after PU power management done. + */ + imx_anatop_pu_enable(true); + imx_gpc_xpu_enable(); } diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index b1aa87a194db..0c1f73b0161e 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -572,6 +572,12 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk_register_clkdev(clk[arm], NULL, "cpu0"); clk_register_clkdev(clk[pll4_post_div], "pll4_post_div", NULL); clk_register_clkdev(clk[pll4_audio], "pll4_audio", NULL); + clk_register_clkdev(clk[gpu3d_core], "gpu3d_core", NULL); + clk_register_clkdev(clk[gpu3d_shader], "gpu3d_shader", NULL); + clk_register_clkdev(clk[gpu2d_core], "gpu2d_core", NULL); + clk_register_clkdev(clk[gpu2d_axi], "gpu2d_axi", NULL); + clk_register_clkdev(clk[openvg_axi], "openvg_axi", NULL); + clk_register_clkdev(clk[vpu_axi], "vpu_axi", NULL); if ((imx6q_revision() != IMX_CHIP_REVISION_1_0) || cpu_is_imx6dl()) { clk_set_parent(clk[ldb_di0_sel], clk[pll5_video_div]); diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 32c751df7565..558e95f4aadf 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -132,6 +132,7 @@ extern void imx_gpc_pre_suspend(void); extern void imx_gpc_post_resume(void); extern void imx_gpc_mask_all(void); extern void imx_gpc_restore_all(void); +extern void imx_gpc_xpu_enable(void); extern void imx_anatop_init(void); extern void imx_anatop_pre_suspend(void); extern void imx_anatop_post_resume(void); diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 44a65e9ff1fc..b90fc0aff2f5 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -10,6 +10,7 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include <linux/clk.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/of.h> @@ -20,12 +21,17 @@ #define GPC_IMR1 0x008 #define GPC_PGC_CPU_PDN 0x2a0 +#define GPC_PGC_GPU_PDN 0x260 +#define GPC_CNTR 0x0 +#define GPC_CNTR_xPU_UP_REQ_SHIFT 0x1 #define IMR_NUM 4 static void __iomem *gpc_base; static u32 gpc_wake_irqs[IMR_NUM]; static u32 gpc_saved_imrs[IMR_NUM]; +static struct clk *gpu3d_clk, *gpu3d_shader_clk, *gpu2d_clk, *gpu2d_axi_clk; +static struct clk *openvg_axi_clk, *vpu_clk; void imx_gpc_pre_suspend(void) { @@ -120,6 +126,60 @@ static void imx_gpc_irq_mask(struct irq_data *d) writel_relaxed(val, reg); } +static void imx_gpc_pu_clk_init(void) +{ + if (gpu3d_clk != NULL && gpu3d_shader_clk != NULL + && gpu2d_clk != NULL && gpu2d_axi_clk != NULL + && openvg_axi_clk != NULL && vpu_clk != NULL) + return; + + /* Get gpu&vpu clk for power up PU by GPC */ + gpu3d_clk = clk_get(NULL, "gpu3d_core"); + gpu3d_shader_clk = clk_get(NULL, "gpu3d_shader"); + gpu2d_clk = clk_get(NULL, "gpu2d_core"); + gpu2d_axi_clk = clk_get(NULL, "gpu2d_axi"); + openvg_axi_clk = clk_get(NULL, "openvg_axi"); + vpu_clk = clk_get(NULL, "vpu_axi"); + if (IS_ERR(gpu3d_clk) || IS_ERR(gpu3d_shader_clk) + || IS_ERR(gpu2d_clk) || IS_ERR(gpu2d_axi_clk) + || IS_ERR(openvg_axi_clk) || IS_ERR(vpu_clk)) + printk(KERN_ERR "%s: failed to get clk!\n", __func__); +} + +static void imx_pu_clk(bool enable) +{ + if (enable) { + clk_prepare_enable(gpu3d_clk); + clk_prepare_enable(gpu3d_shader_clk); + clk_prepare_enable(vpu_clk); + clk_prepare_enable(gpu2d_clk); + clk_prepare_enable(gpu2d_axi_clk); + clk_prepare_enable(openvg_axi_clk); + } else { + clk_disable_unprepare(gpu3d_clk); + clk_disable_unprepare(gpu3d_shader_clk); + clk_disable_unprepare(vpu_clk); + clk_disable_unprepare(gpu2d_clk); + clk_disable_unprepare(gpu2d_axi_clk); + clk_disable_unprepare(openvg_axi_clk); + } +} + +void imx_gpc_xpu_enable(void) +{ + /* + * PU is turned off in uboot, so we need to turn it on here + * to avoid kernel hang during GPU init, will remove + * this code after PU power management done. + */ + imx_gpc_pu_clk_init(); + imx_pu_clk(true); + writel_relaxed(1, gpc_base + GPC_PGC_GPU_PDN); + writel_relaxed(1 << GPC_CNTR_xPU_UP_REQ_SHIFT, gpc_base + GPC_CNTR); + while (readl_relaxed(gpc_base + GPC_CNTR) & 0x2) + ; +} + void __init imx_gpc_init(void) { struct device_node *np; |