summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-imx/anatop.c57
-rw-r--r--arch/arm/mach-imx/clk-imx6q.c6
-rw-r--r--arch/arm/mach-imx/common.h1
-rw-r--r--arch/arm/mach-imx/gpc.c60
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;