video: tegra: host: fix gk20a rail gate/ungate sequence
Mayuresh Kulkarni [Fri, 12 Jul 2013 16:53:55 +0000 (21:53 +0530)]
bug 1324512

Change-Id: I6d95c5ae454be6e5a3c377a23fc0283d576aa016
Signed-off-by: Mayuresh Kulkarni <mkulkarni@nvidia.com>
Reviewed-on: http://git-master/r/253397
Reviewed-by: Mandar Padmawar <mpadmawar@nvidia.com>
Tested-by: Mandar Padmawar <mpadmawar@nvidia.com>

arch/arm/mach-tegra/powergate-priv.h
arch/arm/mach-tegra/powergate-t12x.c
arch/arm/mach-tegra/powergate.c
drivers/video/tegra/host/gk20a/gk20a.c

index faa6ee8..50ca510 100644 (file)
@@ -107,6 +107,8 @@ struct powergate_ops {
        bool (*powergate_check_clamping)(int id);
 
        bool (*powergate_skip)(int id);
+
+       bool (*powergate_is_powered)(int id);
 };
 
 void get_clk_info(struct powergate_partition_info *pg_info);
index 8f4172e..2aba6a1 100644 (file)
@@ -240,6 +240,8 @@ static struct powergate_partition_info tegra12x_powergate_partition_info[] = {
 
 static DEFINE_SPINLOCK(tegra12x_powergate_lock);
 
+static struct regulator *gpu_reg;
+
 #define HOTRESET_READ_COUNT    5
 static bool tegra12x_stable_hotreset_check(u32 stat_reg, u32 *stat)
 {
@@ -380,9 +382,12 @@ static int tegra12x_gpu_powergate(int id, struct powergate_partition_info *pg_in
 
        udelay(10);
 
-       /* TBD: call regulator api to turn off VDD_GPU */
-       if (0)
-               goto err_power_off;
+       if (gpu_reg && tegra_powergate_is_powered(id)) {
+               ret = regulator_disable(gpu_reg);
+               if (ret)
+                       goto err_power_off;
+       } else
+               pr_info("No GPU regulator?\n");
 
        return 0;
 
@@ -391,30 +396,22 @@ err_power_off:
        return ret;
 }
 
-int hack_tegra12x_gpu_unpowergate(void)
+static int tegra12x_gpu_unpowergate(int id,
+       struct powergate_partition_info *pg_info)
 {
-       int ret;
-       int id = TEGRA_POWERGATE_GPU;
-       struct powergate_partition_info *pg_info =
-                                       &tegra12x_powergate_partition_info[id];
-       struct regulator * gpu_reg;
-
-       if (!tegra_platform_is_silicon())
-               return 0;
+       int ret = 0;
 
-       printk("%s(): start\n", __func__);
-       gpu_reg = regulator_get(NULL, "vdd_gpu");
-       if (IS_ERR_OR_NULL(gpu_reg))
-               BUG_ON(1);
+       if (!gpu_reg) {
+               gpu_reg = regulator_get(NULL, "vdd_gpu");
+               if (IS_ERR_OR_NULL(gpu_reg)) {
+                       WARN(1, "No GPU regulator?\n");
+                       goto err_power;
+               }
+       }
 
-       regulator_set_voltage(gpu_reg, 900000, 900000);
        ret = regulator_enable(gpu_reg);
        if (ret)
-               BUG_ON(1);
-
-       /* TBD: call regulator api to turn on VDD_GPU */
-       if (0)
-               goto err_power;
+               goto err_power;
 
        /* If first clk_ptr is null, fill clk info for the partition */
        if (!pg_info->clk_info[0].clk_ptr)
@@ -443,52 +440,6 @@ int hack_tegra12x_gpu_unpowergate(void)
        udelay(10);
 
        /* Disable all clks enabled earlier. Drivers should enable clks */
-       // partition_clk_disable(pg_info);
-
-       printk("%s(): end\n", __func__);
-       return 0;
-
-err_clk_on:
-       powergate_module(id);
-err_power:
-       WARN(1, "Could not Un-Railgate %d", id);
-       return ret;
-}
-EXPORT_SYMBOL(hack_tegra12x_gpu_unpowergate);
-
-static int tegra12x_gpu_unpowergate(int id, struct powergate_partition_info *pg_info)
-{
-       int ret;
-
-       /* TBD: call regulator api to turn on VDD_GPU */
-       if (0)
-               goto err_power;
-
-       /* If first clk_ptr is null, fill clk info for the partition */
-       if (!pg_info->clk_info[0].clk_ptr)
-               get_clk_info(pg_info);
-
-       /* Un-Powergating fails if all clks are not enabled */
-       ret = partition_clk_enable(pg_info);
-       if (ret)
-               goto err_clk_on;
-
-       udelay(10);
-
-       /* disable clamp */
-       pmc_write(0, PMC_GPU_RG_CNTRL_0);
-
-       udelay(10);
-
-       powergate_partition_deassert_reset(pg_info);
-
-       udelay(10);
-
-       tegra_powergate_mc_flush_done(id);
-
-       udelay(10);
-
-       /* Disable all clks enabled earlier. Drivers should enable clks */
        partition_clk_disable(pg_info);
 
        return 0;
@@ -646,6 +597,20 @@ bool tegra12x_powergate_skip(int id)
        }
 }
 
+bool tegra12x_powergate_is_powered(int id)
+{
+       u32 status = 0;
+
+       if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
+               if (gpu_reg)
+                       return regulator_is_enabled(gpu_reg);
+       } else {
+               status = pmc_read(PWRGATE_STATUS) & (1 << id);
+               return !!status;
+       }
+       return status;
+}
+
 static struct powergate_ops tegra12x_powergate_ops = {
        .soc_name = "tegra12x",
 
@@ -667,6 +632,8 @@ static struct powergate_ops tegra12x_powergate_ops = {
        .powergate_mc_flush_done = tegra12x_powergate_mc_flush_done,
 
        .powergate_skip = tegra12x_powergate_skip,
+
+       .powergate_is_powered = tegra12x_powergate_is_powered,
 };
 
 struct powergate_ops *tegra12x_powergate_init_chip_support(void)
index de2e001..db36a04 100644 (file)
@@ -356,6 +356,11 @@ bool tegra_powergate_is_powered(int id)
        if (id < 0 || id >= pg_ops->num_powerdomains)
                return -EINVAL;
 
+       if (pg_ops->powergate_is_powered)
+               return pg_ops->powergate_is_powered(id);
+       else
+               status = pmc_read(PWRGATE_STATUS) & (1 << id);
+
        status = pmc_read(PWRGATE_STATUS) & (1 << id);
 
        return !!status;
index 6b7cd39..799147a 100644 (file)
@@ -50,8 +50,6 @@
 
 #include "../../../../../../arch/arm/mach-tegra/iomap.h"
 
-extern int hack_tegra12x_gpu_unpowergate(void);
-
 static inline void set_gk20a(struct platform_device *dev, struct gk20a *gk20a)
 {
        nvhost_set_private_data(dev, gk20a);
@@ -108,38 +106,39 @@ struct nvhost_device_data tegra_gk20a_info = {
        .waitbases,
        .modulemutexes,
        */
-       .class         = NV_GRAPHICS_GPU_CLASS_ID,
-       .clocks = {{"PLLG_ref", UINT_MAX}, {"pwr", 204000000}, \
-                  {"emc", UINT_MAX}, {} },
-       .powergate_ids = { TEGRA_POWERGATE_GPU, -1 },
+       .class                  = NV_GRAPHICS_GPU_CLASS_ID,
+       .clocks                 = {{"PLLG_ref", UINT_MAX},
+                                  {"pwr", 408000000},
+                                  {"emc", UINT_MAX},
+                                  {} },
+       .powergate_ids          = { TEGRA_POWERGATE_GPU, -1 },
        NVHOST_DEFAULT_CLOCKGATE_DELAY,
-       .powergate_delay = 500,
-       .can_powergate = false,
-       .alloc_hwctx_handler = nvhost_gk20a_alloc_hwctx_handler,
-       .ctrl_ops = &gk20a_ctrl_ops,
-       .moduleid      = NVHOST_MODULE_GPU,
+       .powergate_delay        = 750,
+       .can_powergate          = true,
+       .alloc_hwctx_handler    = nvhost_gk20a_alloc_hwctx_handler,
+       .ctrl_ops               = &gk20a_ctrl_ops,
+       .moduleid               = NVHOST_MODULE_GPU,
 };
 
 struct platform_device tegra_gk20a_device = {
-       .name          = "gk20a",
-       .resource      = gk20a_resources,
+       .name           = "gk20a",
+       .resource       = gk20a_resources,
 #if CONFIG_GK20A_SIM
-       .num_resources = 3, /* this is num ioresource_mem, not the sum */
+       .num_resources  = 3, /* this is num ioresource_mem, not the sum */
 #else
-       .num_resources = 2, /* this is num ioresource_mem, not the sum */
+       .num_resources  = 2, /* this is num ioresource_mem, not the sum */
 #endif
-       .dev           = {
+       .dev            = {
                .platform_data = &tegra_gk20a_info,
        },
 };
 
-
-
 #if CONFIG_GK20A_SIM
 static inline void sim_writel(struct gk20a *g, u32 r, u32 v)
 {
        writel(v, g->sim.regs+r);
 }
+
 static inline u32 sim_readl(struct gk20a *g, u32 r)
 {
        return readl(g->sim.regs+r);
@@ -319,10 +318,12 @@ static inline u32 sim_escape_read_hdr_size(void)
 {
        return 12; /*TBD: fix NV_VGPU_SIM_ESCAPE_READ_HEADER*/
 }
+
 static u32 *sim_send_ring_bfr(struct gk20a *g, u32 byte_offset)
 {
        return (u32 *)(g->sim.send_bfr.kvaddr + byte_offset);
 }
+
 static int rpc_send_message(struct gk20a *g)
 {
        /* calculations done in units of u32s */
@@ -406,7 +407,6 @@ static int rpc_recv_poll(struct gk20a *g)
        return 0;
 }
 
-
 static int issue_rpc_and_wait(struct gk20a *g)
 {
        int err;
@@ -455,7 +455,6 @@ int gk20a_sim_esc_read(struct gk20a *g, char *path, u32 index, u32 count, u32 *d
        return err;
 }
 
-
 #else /*CONFIG_GK20A_SIM*/
 static inline int gk20a_init_sim_support(struct platform_device *dev)
 {
@@ -706,6 +705,9 @@ int nvhost_gk20a_prepare_poweroff(struct platform_device *dev)
 
        nvhost_dbg_fn("");
 
+       if (!g->power_on)
+               return 0;
+
        ret |= gk20a_channel_suspend(g);
 
        ret |= gk20a_fifo_suspend(g);
@@ -729,14 +731,11 @@ int nvhost_gk20a_finalize_poweron(struct platform_device *dev)
        if (g->power_on)
                return 0;
 
-       g->power_on = true;
-
-       /* FIXME: We probably don't need to call this routine, and hence
-        * should remove it.
-        */
-       hack_tegra12x_gpu_unpowergate();
+       /* FIXME: fix this correctly. this is enabling ARCH timer */
        writel(0x1, IO_TO_VIRT(0x700f0000));
 
+       g->power_on = true;
+
        gk20a_writel(g, mc_intr_en_1_r(),
                mc_intr_en_1_inta_disabled_f());