From: Mayuresh Kulkarni Date: Fri, 12 Jul 2013 16:53:55 +0000 (+0530) Subject: video: tegra: host: fix gk20a rail gate/ungate sequence X-Git-Tag: daily-2014.03.25.0_l4t/l4t-r19.1~2936 X-Git-Url: https://nv-tegra.nvidia.com/r/gitweb?p=linux-3.10.git;a=commitdiff_plain;h=ed905c196c283e8d9b474b3ad669e9bd732a387e video: tegra: host: fix gk20a rail gate/ungate sequence bug 1324512 Change-Id: I6d95c5ae454be6e5a3c377a23fc0283d576aa016 Signed-off-by: Mayuresh Kulkarni Reviewed-on: http://git-master/r/253397 Reviewed-by: Mandar Padmawar Tested-by: Mandar Padmawar --- diff --git a/arch/arm/mach-tegra/powergate-priv.h b/arch/arm/mach-tegra/powergate-priv.h index faa6ee8305a..50ca5107913 100644 --- a/arch/arm/mach-tegra/powergate-priv.h +++ b/arch/arm/mach-tegra/powergate-priv.h @@ -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); diff --git a/arch/arm/mach-tegra/powergate-t12x.c b/arch/arm/mach-tegra/powergate-t12x.c index 8f4172e18f0..2aba6a1a90d 100644 --- a/arch/arm/mach-tegra/powergate-t12x.c +++ b/arch/arm/mach-tegra/powergate-t12x.c @@ -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) @@ -442,52 +439,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); @@ -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) diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index de2e0019cda..db36a046dc8 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -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; diff --git a/drivers/video/tegra/host/gk20a/gk20a.c b/drivers/video/tegra/host/gk20a/gk20a.c index 6b7cd394359..799147a91b1 100644 --- a/drivers/video/tegra/host/gk20a/gk20a.c +++ b/drivers/video/tegra/host/gk20a/gk20a.c @@ -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());