diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2011-09-01 08:05:10 +0300 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:49:11 -0800 |
commit | 17bbd9c676aa818a9b28b77b84c1e28cd080b08e (patch) | |
tree | 98db15a91924ee0670afba961658a7a7a79d8ae5 /drivers/video/tegra/host/t30 | |
parent | 4faee0163e39b1bb91b7e987732ae63884c11f88 (diff) |
nvhost: Modularize ACM code
Refactor nvhost_acm.c so that module specific code can be separated from
generic code:
* Module clock and power op descriptions added to channelmap table
* New module busy/idle interface added
* 3D clock scaling for Tegra3 moved behind the module busy/idle API
* 3D power off code moved to 3dctx where it belongs
* Module power on API removed as there were no users
* Get/Set rate moved to Tegra3 specific file
Bug 870791
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/51275
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
(cherry-picked from ebea06768d9c9d351a7d1c8dc6499c97f2f5002d)
Change-Id: I5857c7db4bbf936a694239a4a3493f2cb95426a1
Reviewed-on: http://git-master/r/56268
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Rebase-Id: Reaccd277c8f4fe12a4f7453cc4e787334122a3b8
Diffstat (limited to 'drivers/video/tegra/host/t30')
-rw-r--r-- | drivers/video/tegra/host/t30/Makefile | 3 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/acm_t30.c | 141 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/channel_t30.c | 126 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/debug_t30.c | 28 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/scale3d.c | 354 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/scale3d.h | 49 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/t30.c | 5 | ||||
-rw-r--r-- | drivers/video/tegra/host/t30/t30.h | 2 |
8 files changed, 704 insertions, 4 deletions
diff --git a/drivers/video/tegra/host/t30/Makefile b/drivers/video/tegra/host/t30/Makefile index 8f4eb4191da6..7e77d8af701c 100644 --- a/drivers/video/tegra/host/t30/Makefile +++ b/drivers/video/tegra/host/t30/Makefile @@ -1,6 +1,9 @@ nvhost-t30-objs = \ t30.o \ channel_t30.o \ + scale3d.o \ + debug_t30.o \ + acm_t30.o \ 3dctx_t30.o obj-$(CONFIG_TEGRA_GRHOST) += nvhost-t30.o diff --git a/drivers/video/tegra/host/t30/acm_t30.c b/drivers/video/tegra/host/t30/acm_t30.c new file mode 100644 index 000000000000..6c058be9c734 --- /dev/null +++ b/drivers/video/tegra/host/t30/acm_t30.c @@ -0,0 +1,141 @@ +/* + * drivers/video/tegra/host/t30/acm_t30.c + * + * Tegra Graphics Host Power Management for Tegra3 + * + * Copyright (c) 2010-2011, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/slab.h> +#include <linux/err.h> +#include "../dev.h" +#include "../chip_support.h" +#include "../nvhost_acm.h" +#include "t30.h" +DEFINE_MUTEX(client_list_lock); + +struct nvhost_module_client { + struct list_head node; + unsigned long rate[NVHOST_MODULE_MAX_CLOCKS]; + void *priv; +}; + +int t30_acm_get_rate(struct nvhost_module *mod, unsigned long *rate, + int index) +{ + struct clk *c; + + c = mod->clk[index]; + if (IS_ERR_OR_NULL(c)) + return -EINVAL; + + /* Need to enable client to get correct rate */ + nvhost_module_busy(mod); + *rate = clk_get_rate(c); + nvhost_module_idle(mod); + return 0; +} + +static int t30_acm_update_rate(struct nvhost_module *mod, int index) +{ + unsigned long rate = 0; + struct nvhost_module_client *m; + + if (!mod->clk[index]) + return -EINVAL; + + list_for_each_entry(m, &mod->client_list, node) { + rate = max(m->rate[index], rate); + } + if (!rate) + rate = clk_round_rate(mod->clk[index], + mod->desc->clocks[index].default_rate); + + return clk_set_rate(mod->clk[index], rate); +} + +int t30_acm_set_rate(struct nvhost_module *mod, void *priv, + unsigned long rate, int index) +{ + struct nvhost_module_client *m; + int ret; + + mutex_lock(&client_list_lock); + list_for_each_entry(m, &mod->client_list, node) { + if (m->priv == priv) { + rate = clk_round_rate(mod->clk[index], rate); + m->rate[index] = rate; + break; + } + } + ret = t30_acm_update_rate(mod, index); + mutex_unlock(&client_list_lock); + return ret; +} + +int t30_acm_add_client(struct nvhost_module *mod, void *priv) +{ + int i; + unsigned long rate; + struct nvhost_module_client *client; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + INIT_LIST_HEAD(&client->node); + client->priv = priv; + + for (i = 0; i < mod->num_clks; i++) { + rate = clk_round_rate(mod->clk[i], + mod->desc->clocks[i].default_rate); + client->rate[i] = rate; + } + mutex_lock(&client_list_lock); + list_add_tail(&client->node, &mod->client_list); + mutex_unlock(&client_list_lock); + return 0; +} + +void t30_acm_remove_client(struct nvhost_module *mod, void *priv) +{ + int i; + struct nvhost_module_client *m; + + mutex_lock(&client_list_lock); + list_for_each_entry(m, &mod->client_list, node) { + if (priv == m->priv) { + list_del(&m->node); + break; + } + } + m->priv = NULL; + kfree(m); + for (i = 0; i < mod->num_clks; i++) + t30_acm_update_rate(mod, i); + mutex_unlock(&client_list_lock); +} + +int nvhost_init_t30_acm(struct nvhost_master *host) +{ + host->op.acm.get_rate = t30_acm_get_rate; + host->op.acm.set_rate = t30_acm_set_rate; + host->op.acm.add_client = t30_acm_add_client; + host->op.acm.remove_client = t30_acm_remove_client; + + return 0; +} diff --git a/drivers/video/tegra/host/t30/channel_t30.c b/drivers/video/tegra/host/t30/channel_t30.c index 6ec2f39c5711..43cd459bd210 100644 --- a/drivers/video/tegra/host/t30/channel_t30.c +++ b/drivers/video/tegra/host/t30/channel_t30.c @@ -20,11 +20,132 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "3dctx_t30.h" +#include <linux/mutex.h> +#include <mach/powergate.h> #include "../dev.h" #include "../t20/channel_t20.h" #include "../t20/hardware_t20.h" #include "../t20/t20.h" +#include "../t20/syncpt_t20.h" +#include "../3dctx_common.h" +#include "3dctx_t30.h" +#include "scale3d.h" + +#define NVMODMUTEX_2D_FULL (1) +#define NVMODMUTEX_2D_SIMPLE (2) +#define NVMODMUTEX_2D_SB_A (3) +#define NVMODMUTEX_2D_SB_B (4) +#define NVMODMUTEX_3D (5) +#define NVMODMUTEX_DISPLAYA (6) +#define NVMODMUTEX_DISPLAYB (7) +#define NVMODMUTEX_VI (8) +#define NVMODMUTEX_DSI (9) +#define NV_FIFO_READ_TIMEOUT 200000 + +#define HOST_EMC_FLOOR 300000000 +#ifndef TEGRA_POWERGATE_3D1 +#define TEGRA_POWERGATE_3D1 -1 +#endif + +const struct nvhost_channeldesc nvhost_t30_channelmap[] = { +{ + /* channel 0 */ + .name = "display", + .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) | + BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) | + BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) | + BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1), + .modulemutexes = BIT(NVMODMUTEX_DISPLAYA) | BIT(NVMODMUTEX_DISPLAYB), + .module = { + NVHOST_MODULE_NO_POWERGATING, + NVHOST_DEFAULT_POWERDOWN_DELAY, + }, +}, +{ + /* channel 1 */ + .name = "gr3d", + .syncpts = BIT(NVSYNCPT_3D), + .waitbases = BIT(NVWAITBASE_3D), + .modulemutexes = BIT(NVMODMUTEX_3D), + .class = NV_GRAPHICS_3D_CLASS_ID, + .module = { + .prepare_poweroff = nvhost_3dctx_prepare_power_off, + .busy = nvhost_scale3d_notify_busy, + .idle = nvhost_scale3d_notify_idle, + .init = nvhost_scale3d_init, + .deinit = nvhost_scale3d_deinit, + .suspend = nvhost_scale3d_suspend, + .clocks = {{"gr3d", UINT_MAX}, + {"gr3d2", UINT_MAX}, + {"emc", HOST_EMC_FLOOR} }, + .powergate_ids = {TEGRA_POWERGATE_3D, + TEGRA_POWERGATE_3D1}, + NVHOST_DEFAULT_POWERDOWN_DELAY, + }, +}, +{ + /* channel 2 */ + .name = "gr2d", + .syncpts = BIT(NVSYNCPT_2D_0) | BIT(NVSYNCPT_2D_1), + .waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1), + .modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) | + BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B), + .module = { + .clocks = {{"gr2d", 0}, + {"epp", 0}, + {"emc", HOST_EMC_FLOOR} }, + NVHOST_MODULE_NO_POWERGATING, + .powerdown_delay = 0, + }, +}, +{ + /* channel 3 */ + .name = "isp", + .syncpts = 0, + .module = { + NVHOST_MODULE_NO_POWERGATING, + NVHOST_DEFAULT_POWERDOWN_DELAY, + }, +}, +{ + /* channel 4 */ + .name = "vi", + .syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) | + BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) | + BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) | + BIT(NVSYNCPT_VI_ISP_4), + .modulemutexes = BIT(NVMODMUTEX_VI), + .exclusive = true, + .module = { + NVHOST_MODULE_NO_POWERGATING, + NVHOST_DEFAULT_POWERDOWN_DELAY, + }, +}, +{ + /* channel 5 */ + .name = "mpe", + .syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) | + BIT(NVSYNCPT_MPE_WR_SAFE), + .waitbases = BIT(NVWAITBASE_MPE), + .class = NV_VIDEO_ENCODE_MPEG_CLASS_ID, + .exclusive = true, + .keepalive = true, + .module = { + .clocks = {{"mpe", UINT_MAX}, {"emc", UINT_MAX}, {} }, + .powergate_ids = {TEGRA_POWERGATE_MPE, -1}, + NVHOST_DEFAULT_POWERDOWN_DELAY, + }, +}, +{ + /* channel 6 */ + .name = "dsi", + .syncpts = BIT(NVSYNCPT_DSI), + .modulemutexes = BIT(NVMODMUTEX_DSI), + .module = { + NVHOST_MODULE_NO_POWERGATING, + NVHOST_DEFAULT_POWERDOWN_DELAY, + }, +} }; #define NVHOST_CHANNEL_BASE 0 @@ -46,13 +167,12 @@ static inline void __iomem *t30_channel_aperture(void __iomem *p, int ndx) return p; } - static int t30_channel_init(struct nvhost_channel *ch, struct nvhost_master *dev, int index) { ch->dev = dev; ch->chid = index; - ch->desc = nvhost_t20_channelmap + index; + ch->desc = nvhost_t30_channelmap + index; mutex_init(&ch->reflock); mutex_init(&ch->submitlock); diff --git a/drivers/video/tegra/host/t30/debug_t30.c b/drivers/video/tegra/host/t30/debug_t30.c new file mode 100644 index 000000000000..b7d88a852780 --- /dev/null +++ b/drivers/video/tegra/host/t30/debug_t30.c @@ -0,0 +1,28 @@ +/* + * drivers/video/tegra/host/t30/debug_t30.c + * + * Copyright (C) 2011 NVIDIA Corporation + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../dev.h" +#include "scale3d.h" +#include "../t20/t20.h" +#include "../chip_support.h" + +int nvhost_init_t30_debug_support(struct nvhost_master *host) +{ + nvhost_init_t20_debug_support(host); + host->op.debug.debug_init = nvhost_scale3d_debug_init; + + return 0; +} diff --git a/drivers/video/tegra/host/t30/scale3d.c b/drivers/video/tegra/host/t30/scale3d.c new file mode 100644 index 000000000000..63d52abf2bdf --- /dev/null +++ b/drivers/video/tegra/host/t30/scale3d.c @@ -0,0 +1,354 @@ +/* + * drivers/video/tegra/host/t20/scale3d.c + * + * Tegra Graphics Host 3D clock scaling + * + * Copyright (c) 2010-2011, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * 3d clock scaling + * + * module3d_notify_busy() is called upon submit, module3d_notify_idle() is + * called when all outstanding submits are completed. Idle times are measured + * over a fixed time period (scale3d.p_period). If the 3d module idle time + * percentage goes over the limit (set in scale3d.p_idle_max), 3d clocks are + * scaled down. If the percentage goes under the minimum limit (set in + * scale3d.p_idle_min), 3d clocks are scaled up. An additional test is made + * over the time frame given in scale3d.p_fast_response for clocking up + * quickly in response to sudden load peaks. + */ + +#include <linux/debugfs.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <mach/clk.h> +#include <mach/hardware.h> +#include "scale3d.h" +#include "../dev.h" + +static int scale3d_is_enabled(void); +static void scale3d_enable(int enable); + +/* + * debugfs parameters to control 3d clock scaling test + * + * period - time period for clock rate evaluation + * fast_response - time period for evaluation of 'busy' spikes + * idle_min - if less than [idle_min] percent idle over [fast_response] + * microseconds, clock up. + * idle_max - if over [idle_max] percent idle over [period] microseconds, + * clock down. + * max_scale - limits rate changes to no less than (100 - max_scale)% or + * (100 + 2 * max_scale)% of current clock rate + * verbosity - set above 5 for debug printouts + */ + +struct scale3d_info_rec { + struct mutex lock; /* lock for timestamps etc */ + int enable; + int init; + ktime_t idle_frame; + ktime_t fast_frame; + ktime_t last_idle; + ktime_t last_busy; + int is_idle; + unsigned long idle_total; + struct work_struct work; + unsigned int scale; + unsigned int p_period; + unsigned int p_idle_min; + unsigned int p_idle_max; + unsigned int p_fast_response; + unsigned int p_verbosity; + struct clk *clk_3d; + struct clk *clk_3d2; +}; + +static struct scale3d_info_rec scale3d; + +static void scale3d_clocks(unsigned long percent) +{ + unsigned long hz, curr; + + if (!tegra_is_clk_enabled(scale3d.clk_3d)) + return; + + if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) + if (!tegra_is_clk_enabled(scale3d.clk_3d2)) + return; + + curr = clk_get_rate(scale3d.clk_3d); + hz = percent * (curr / 100); + + if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) + clk_set_rate(scale3d.clk_3d2, 0); + clk_set_rate(scale3d.clk_3d, hz); +} + +static void scale3d_clocks_handler(struct work_struct *work) +{ + unsigned int scale; + + mutex_lock(&scale3d.lock); + scale = scale3d.scale; + mutex_unlock(&scale3d.lock); + + if (scale != 0) + scale3d_clocks(scale); +} + +void nvhost_scale3d_suspend(struct nvhost_module *mod) +{ + cancel_work_sync(&scale3d.work); +} + +/* set 3d clocks to max */ +static void reset_3d_clocks(void) +{ + unsigned long hz; + + hz = clk_round_rate(scale3d.clk_3d, UINT_MAX); + clk_set_rate(scale3d.clk_3d, hz); + if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) + clk_set_rate(scale3d.clk_3d2, hz); +} + +static int scale3d_is_enabled(void) +{ + int enable; + + mutex_lock(&scale3d.lock); + enable = scale3d.enable; + mutex_unlock(&scale3d.lock); + + return enable; +} + +static void scale3d_enable(int enable) +{ + int disable = 0; + + mutex_lock(&scale3d.lock); + + if (enable) + scale3d.enable = 1; + else { + scale3d.enable = 0; + disable = 1; + } + + mutex_unlock(&scale3d.lock); + + if (disable) + reset_3d_clocks(); +} + +static void reset_scaling_counters(ktime_t time) +{ + scale3d.idle_total = 0; + scale3d.last_idle = time; + scale3d.last_busy = time; + scale3d.idle_frame = time; +} + +static void scaling_state_check(ktime_t time) +{ + unsigned long dt; + + /* check for load peaks */ + dt = (unsigned long) ktime_us_delta(time, scale3d.fast_frame); + if (dt > scale3d.p_fast_response) { + unsigned long idleness = (scale3d.idle_total * 100) / dt; + scale3d.fast_frame = time; + /* if too busy, scale up */ + if (idleness < scale3d.p_idle_min) { + if (scale3d.p_verbosity > 5) + pr_info("scale3d: %ld%% busy\n", + 100 - idleness); + + scale3d.scale = 200; + schedule_work(&scale3d.work); + reset_scaling_counters(time); + return; + } + } + + dt = (unsigned long) ktime_us_delta(time, scale3d.idle_frame); + if (dt > scale3d.p_period) { + unsigned long idleness = (scale3d.idle_total * 100) / dt; + + if (scale3d.p_verbosity > 5) + pr_info("scale3d: idle %lu, ~%lu%%\n", + scale3d.idle_total, idleness); + + if (idleness > scale3d.p_idle_max) { + /* if idle time is high, clock down */ + scale3d.scale = 100 - (idleness - scale3d.p_idle_min); + schedule_work(&scale3d.work); + } else if (idleness < scale3d.p_idle_min) { + /* if idle time is low, clock up */ + scale3d.scale = 200; + schedule_work(&scale3d.work); + } + reset_scaling_counters(time); + } +} + +void nvhost_scale3d_notify_idle(struct nvhost_module *mod) +{ + mutex_lock(&scale3d.lock); + + if (!scale3d.enable) + goto done; + + scale3d.last_idle = ktime_get(); + scale3d.is_idle = 1; + + scaling_state_check(scale3d.last_idle); + +done: + mutex_unlock(&scale3d.lock); +} + +void nvhost_scale3d_notify_busy(struct nvhost_module *mod) +{ + unsigned long idle; + ktime_t t; + + mutex_lock(&scale3d.lock); + + if (!scale3d.enable) + goto done; + + t = ktime_get(); + + if (scale3d.is_idle) { + scale3d.last_busy = t; + idle = (unsigned long) + ktime_us_delta(scale3d.last_busy, scale3d.last_idle); + scale3d.idle_total += idle; + scale3d.is_idle = 0; + } + + scaling_state_check(t); + +done: + mutex_unlock(&scale3d.lock); +} + +void nvhost_scale3d_reset() +{ + ktime_t t = ktime_get(); + mutex_lock(&scale3d.lock); + reset_scaling_counters(t); + mutex_unlock(&scale3d.lock); +} + +/* + * debugfs parameters to control 3d clock scaling + */ + +void nvhost_scale3d_debug_init(struct dentry *de) +{ + struct dentry *d, *f; + + d = debugfs_create_dir("scaling", de); + if (!d) { + pr_err("scale3d: can\'t create debugfs directory\n"); + return; + } + +#define CREATE_SCALE3D_FILE(fname) \ + do {\ + f = debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, d,\ + &scale3d.p_##fname);\ + if (NULL == f) {\ + pr_err("scale3d: can\'t create file " #fname "\n");\ + return;\ + } \ + } while (0) + + CREATE_SCALE3D_FILE(fast_response); + CREATE_SCALE3D_FILE(idle_min); + CREATE_SCALE3D_FILE(idle_max); + CREATE_SCALE3D_FILE(period); + CREATE_SCALE3D_FILE(verbosity); +#undef CREATE_SCALE3D_FILE +} + +static ssize_t enable_3d_scaling_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + ssize_t res; + + res = snprintf(buf, PAGE_SIZE, "%d\n", scale3d_is_enabled()); + + return res; +} + +static ssize_t enable_3d_scaling_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val = 0; + + if (strict_strtoul(buf, 10, &val) < 0) + return -EINVAL; + + scale3d_enable(val); + + return count; +} + +static DEVICE_ATTR(enable_3d_scaling, S_IRUGO | S_IWUSR, + enable_3d_scaling_show, enable_3d_scaling_store); + +void nvhost_scale3d_init(struct device *d, struct nvhost_module *mod) +{ + if (!scale3d.init) { + int error; + mutex_init(&scale3d.lock); + + scale3d.clk_3d = mod->clk[0]; + if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) + scale3d.clk_3d2 = mod->clk[1]; + + INIT_WORK(&scale3d.work, scale3d_clocks_handler); + + /* set scaling parameter defaults */ + scale3d.enable = 0; + scale3d.p_period = 1200000; + scale3d.p_idle_min = 17; + scale3d.p_idle_max = 17; + scale3d.p_fast_response = 16000; + scale3d.p_verbosity = 0; + + error = device_create_file(d, &dev_attr_enable_3d_scaling); + if (error) + dev_err(d, "failed to create sysfs attributes"); + + scale3d.init = 1; + } + + nvhost_scale3d_reset(); +} + +void nvhost_scale3d_deinit(struct device *dev, struct nvhost_module *mod) +{ + device_remove_file(dev, &dev_attr_enable_3d_scaling); + scale3d.init = 0; +} diff --git a/drivers/video/tegra/host/t30/scale3d.h b/drivers/video/tegra/host/t30/scale3d.h new file mode 100644 index 000000000000..e6d1a40f53e0 --- /dev/null +++ b/drivers/video/tegra/host/t30/scale3d.h @@ -0,0 +1,49 @@ +/* + * drivers/video/tegra/host/t30/scale3d.h + * + * Tegra Graphics Host 3D Clock Scaling + * + * Copyright (c) 2010-2011, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NVHOST_T30_SCALE3D_H +#define NVHOST_T30_SCALE3D_H + +struct nvhost_module; +struct device; +struct dentry; + +/* Initialization and de-initialization for module */ +void nvhost_scale3d_init(struct device *, struct nvhost_module *); +void nvhost_scale3d_deinit(struct device *, struct nvhost_module *); + +/* Suspend is called when powering down module */ +void nvhost_scale3d_suspend(struct nvhost_module *); + +/* reset 3d module load counters, called on resume */ +void nvhost_scale3d_reset(void); + +/* + * call when performing submit to notify scaling mechanism that 3d module is + * in use + */ +void nvhost_scale3d_notify_busy(struct nvhost_module *); +void nvhost_scale3d_notify_idle(struct nvhost_module *); + +void nvhost_scale3d_debug_init(struct dentry *de); + +#endif diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c index c7a5011cb953..00e0f648afcc 100644 --- a/drivers/video/tegra/host/t30/t30.c +++ b/drivers/video/tegra/host/t30/t30.c @@ -34,7 +34,7 @@ int nvhost_init_t30_support(struct nvhost_master *host) err = nvhost_init_t20_cdma_support(host); if (err) return err; - err = nvhost_init_t20_debug_support(host); + err = nvhost_init_t30_debug_support(host); if (err) return err; err = nvhost_init_t20_syncpt_support(host); @@ -46,5 +46,8 @@ int nvhost_init_t30_support(struct nvhost_master *host) err = nvhost_init_t20_cpuaccess_support(host); if (err) return err; + err = nvhost_init_t30_acm(host); + if (err) + return err; return 0; } diff --git a/drivers/video/tegra/host/t30/t30.h b/drivers/video/tegra/host/t30/t30.h index 3ea69631bf2e..bbc88bbb81f0 100644 --- a/drivers/video/tegra/host/t30/t30.h +++ b/drivers/video/tegra/host/t30/t30.h @@ -25,5 +25,7 @@ #include "../t20/t20.h" int nvhost_init_t30_channel_support(struct nvhost_master *); +int nvhost_init_t30_debug_support(struct nvhost_master *); +int nvhost_init_t30_acm(struct nvhost_master *); #endif /* _NVHOST_T30_H_ */ |