summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorTom Cherry <tcherry@nvidia.com>2012-05-23 12:06:13 -0700
committerTom Cherry <tcherry@nvidia.com>2012-05-23 12:06:13 -0700
commita168c03bd97fd9761218779623db0cec09fa8f4a (patch)
tree521d2b51904da963d771c24fd9b142cc416f8259 /drivers/video
parent11fb7d0e35d56230919eb91bee1aa138a10b8416 (diff)
parentc7e3189c1802c2a6552eec960f521a1891529892 (diff)
Merge commit 'main-ics-2012.05.22-B3' into HEAD
Conflicts: arch/arm/mach-tegra/pm.c drivers/media/video/tegra/nvavp/nvavp_dev.c drivers/power/smb349-charger.c include/linux/smb349-charger.h include/trace/events/power.h Change-Id: Ia8c82e2acfe3463ae6778bdd03aac8da104f7ad3
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/mx3fb.c5
-rw-r--r--drivers/video/tegra/Kconfig18
-rw-r--r--drivers/video/tegra/dc/Makefile1
-rw-r--r--drivers/video/tegra/dc/dc.c374
-rw-r--r--drivers/video/tegra/dc/dc_config.c246
-rw-r--r--drivers/video/tegra/dc/dc_config.h148
-rw-r--r--drivers/video/tegra/dc/dc_priv.h19
-rw-r--r--drivers/video/tegra/dc/dc_reg.h6
-rw-r--r--drivers/video/tegra/dc/dsi.c128
-rw-r--r--drivers/video/tegra/dc/ext/Makefile1
-rw-r--r--drivers/video/tegra/dc/ext/dev.c41
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h2
-rw-r--r--drivers/video/tegra/dc/ext/util.c2
-rw-r--r--drivers/video/tegra/dc/hdmi.c182
-rw-r--r--drivers/video/tegra/dc/rgb.c8
-rw-r--r--drivers/video/tegra/fb.c53
-rw-r--r--drivers/video/tegra/host/Makefile3
-rw-r--r--drivers/video/tegra/host/bus.c82
-rw-r--r--drivers/video/tegra/host/bus.h38
-rw-r--r--drivers/video/tegra/host/bus_client.c72
-rw-r--r--drivers/video/tegra/host/chip_support.c56
-rw-r--r--drivers/video/tegra/host/chip_support.h33
-rw-r--r--drivers/video/tegra/host/debug.c20
-rw-r--r--drivers/video/tegra/host/dev.c96
-rw-r--r--drivers/video/tegra/host/dev.h16
-rw-r--r--drivers/video/tegra/host/dsi/dsi.c3
-rw-r--r--drivers/video/tegra/host/gr2d/gr2d.c3
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d.c85
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.c6
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.c8
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.c203
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.h2
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.c21
-rw-r--r--drivers/video/tegra/host/host1x/host1x_debug.c17
-rw-r--r--drivers/video/tegra/host/host1x/host1x_hwctx.h1
-rw-r--r--drivers/video/tegra/host/host1x/host1x_intr.c77
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.c34
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.h5
-rw-r--r--drivers/video/tegra/host/isp/isp.c3
-rw-r--r--drivers/video/tegra/host/mpe/mpe.c61
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c55
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c142
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.h10
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c49
-rw-r--r--drivers/video/tegra/host/nvhost_channel.h35
-rw-r--r--drivers/video/tegra/host/nvhost_hwctx.h2
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c48
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h1
-rw-r--r--drivers/video/tegra/host/nvhost_job.c7
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c55
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.h11
-rw-r--r--drivers/video/tegra/host/t20/t20.c71
-rw-r--r--drivers/video/tegra/host/t20/t20.h11
-rw-r--r--drivers/video/tegra/host/t30/t30.c84
-rw-r--r--drivers/video/tegra/host/t30/t30.h9
-rw-r--r--drivers/video/tegra/host/vi/vi.c3
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap.h10
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c6
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c33
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.h2
63 files changed, 1922 insertions, 907 deletions
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 473875a..5e15a92 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -1103,13 +1103,8 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var,
if (mx3_fbi->txd)
async_tx_ack(mx3_fbi->txd);
-<<<<<<< HEAD
- txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg +
- mx3_fbi->cur_ipu_buf, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT);
-=======
txd = dmaengine_prep_slave_sg(dma_chan, sg +
mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers
if (!txd) {
dev_err(fbi->device,
"Error preparing a DMA transaction descriptor.\n");
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
index 7de2626..59e2778 100644
--- a/drivers/video/tegra/Kconfig
+++ b/drivers/video/tegra/Kconfig
@@ -53,7 +53,7 @@ config NVMAP_RECLAIM_UNPINNED_VM
config NVMAP_ALLOW_SYSMEM
bool "Allow physical system memory to be used by nvmap"
depends on TEGRA_NVMAP
- default y
+ default n
help
Say Y here to allow nvmap to use physical system memory (i.e.,
shared with the operating system but not translated through
@@ -85,6 +85,22 @@ config NVMAP_CARVEOUT_COMPACTOR
heap and retries the failed allocation.
Say Y here to let nvmap to keep carveout fragmentation under control.
+config NVMAP_PAGE_POOLS
+ bool "Use page pools to reduce allocation overhead"
+ depends on TEGRA_NVMAP
+ default y
+ help
+ say Y here to reduce the alloction overhead, which is significant
+ for uncached, writecombine and inner cacheable memories as it
+ involves changing page attributes during every allocation per page
+ and flushing cache. Alloc time is reduced by allcoating the pages
+ ahead and keeping them aside. The reserved pages would be released
+ when system is low on memory and acquired back during release of
+ memory.
+
+config NVMAP_PAGE_POOL_SIZE
+ hex
+ default 0x0
config NVMAP_VPR
bool "Enable VPR Heap."
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
index 01f1391..ebe9e89 100644
--- a/drivers/video/tegra/dc/Makefile
+++ b/drivers/video/tegra/dc/Makefile
@@ -7,4 +7,5 @@ obj-y += edid.o
obj-y += nvsd.o
obj-y += dsi.o
obj-y += dc_sysfs.o
+obj-y += dc_config.o
obj-$(CONFIG_TEGRA_DC_EXTENSIONS) += ext/
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 5203fbb..55d3fcc 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -23,7 +23,6 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mutex.h>
@@ -34,6 +33,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/backlight.h>
+#include <linux/gpio.h>
#include <video/tegrafb.h>
#include <drm/drm_fixed.h>
#ifdef CONFIG_SWITCH
@@ -49,6 +49,7 @@
#include <mach/latency_allowance.h>
#include "dc_reg.h"
+#include "dc_config.h"
#include "dc_priv.h"
#include "nvsd.h"
@@ -64,9 +65,21 @@
#define ALL_UF_INT (0)
#endif
-static int calc_refresh(const struct tegra_dc_mode *m);
-
static int no_vsync;
+static struct fb_videomode tegra_dc_hdmi_fallback_mode = {
+ .refresh = 60,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = KHZ2PICOS(25200),
+ .hsync_len = 96, /* h_sync_width */
+ .vsync_len = 2, /* v_sync_width */
+ .left_margin = 48, /* h_back_porch */
+ .upper_margin = 33, /* v_back_porch */
+ .right_margin = 16, /* h_front_porch */
+ .lower_margin = 10, /* v_front_porch */
+ .vmode = 0,
+ .sync = 0,
+};
static void _tegra_dc_controller_disable(struct tegra_dc *dc);
@@ -81,25 +94,14 @@ struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
DEFINE_MUTEX(shared_lock);
-static const struct {
- bool h;
- bool v;
-} can_filter[] = {
- /* Window A has no filtering */
- { false, false },
- /* Window B has both H and V filtering */
- { true, true },
- /* Window C has only H filtering */
- { false, true },
-};
-static inline bool win_use_v_filter(const struct tegra_dc_win *win)
+static inline bool win_use_v_filter(struct tegra_dc *dc, const struct tegra_dc_win *win)
{
- return can_filter[win->idx].v &&
+ return tegra_dc_feature_has_filter(dc, win->idx, HAS_V_FILTER) &&
win->h.full != dfixed_const(win->out_h);
}
-static inline bool win_use_h_filter(const struct tegra_dc_win *win)
+static inline bool win_use_h_filter(struct tegra_dc *dc, const struct tegra_dc_win *win)
{
- return can_filter[win->idx].h &&
+ return tegra_dc_feature_has_filter(dc, win->idx, HAS_H_FILTER) &&
win->w.full != dfixed_const(win->out_w);
}
@@ -141,14 +143,32 @@ static inline int tegra_dc_fmt_bpp(int fmt)
case TEGRA_WIN_FMT_YUV422RA:
return 8;
+ /* YUYV packed into 32-bits */
case TEGRA_WIN_FMT_YCbCr422:
case TEGRA_WIN_FMT_YUV422:
- /* FIXME: need to know the bpp of these formats */
- return 0;
+ return 16;
}
return 0;
}
+static inline bool tegra_dc_is_yuv(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422:
+ case TEGRA_WIN_FMT_YUV422:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return true;
+ }
+ return false;
+}
+
static inline bool tegra_dc_is_yuv_planar(int fmt)
{
switch (fmt) {
@@ -171,6 +191,34 @@ static inline bool tegra_dc_is_yuv_planar(int fmt)
print(data, buff); \
} while (0)
+#define print_mode_info(dc, mode) do { \
+ trace_printk("%s:Mode settings: " \
+ "ref_to_sync: H = %d V = %d, " \
+ "sync_width: H = %d V = %d, " \
+ "back_porch: H = %d V = %d, " \
+ "active: H = %d V = %d, " \
+ "front_porch: H = %d V = %d, " \
+ "pclk = %d, stereo mode = %d\n", \
+ dc->ndev->name, \
+ mode.h_ref_to_sync, mode.v_ref_to_sync, \
+ mode.h_sync_width, mode.v_sync_width, \
+ mode.h_back_porch, mode.v_back_porch, \
+ mode.h_active, mode.v_active, \
+ mode.h_front_porch, mode.v_front_porch, \
+ mode.pclk, mode.stereo_mode); \
+ } while (0)
+
+#define print_underflow_info(dc) do { \
+ trace_printk("%s:Underflow stats: underflows : %llu, " \
+ "undeflows_a : %llu, " \
+ "underflows_b : %llu, " \
+ "underflows_c : %llu\n", \
+ dc->ndev->name, \
+ dc->stats.underflows, \
+ dc->stats.underflows_a, dc->stats.underflows_b, \
+ dc->stats.underflows_c); \
+ } while (0)
+
static void _dump_regs(struct tegra_dc *dc, void *data,
void (* print)(void *data, const char *str))
{
@@ -571,6 +619,20 @@ bool tegra_dc_get_connected(struct tegra_dc *dc)
}
EXPORT_SYMBOL(tegra_dc_get_connected);
+bool tegra_dc_hpd(struct tegra_dc *dc)
+{
+ int sense;
+ int level;
+
+ level = gpio_get_value(dc->out->hotplug_gpio);
+
+ sense = dc->out->flags & TEGRA_DC_OUT_HOTPLUG_MASK;
+
+ return (sense == TEGRA_DC_OUT_HOTPLUG_HIGH && level) ||
+ (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level);
+}
+EXPORT_SYMBOL(tegra_dc_hpd);
+
static u32 blend_topwin(u32 flags)
{
if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE)
@@ -767,6 +829,8 @@ static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
mutex_unlock(&dc->lock);
+ tegra_dc_update_windows(&win, 1);
+
return 0;
}
@@ -828,7 +892,7 @@ static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
/* tegra_dc_get_bandwidth() treats V filter windows as double
* bandwidth, but LA has a seperate client for V filter */
- if (w->idx == 1 && win_use_v_filter(w))
+ if (w->idx == 1 && win_use_v_filter(dc, w))
bw /= 2;
/* our bandwidth is in kbytes/sec, but LA takes MBps.
@@ -946,14 +1010,9 @@ static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
* is of the luma plane's size only. */
bpp = tegra_dc_is_yuv_planar(w->fmt) ?
2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt);
- ret = dc->mode.pclk / 1000UL * bpp / 8 * (win_use_v_filter(w) ? 2 : 1)
+ ret = dc->mode.pclk / 1000UL * bpp / 8 * (win_use_v_filter(dc, w) ? 2 : 1)
* dfixed_trunc(w->w) / w->out_w *
(WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1);
- /*
- * Assuming ~35% efficiency: i.e. if we calculate we need 70MBps, we
- * will request 200MBps from EMC.
- */
- ret = ret * 29 / 10;
return ret;
}
@@ -981,6 +1040,8 @@ static unsigned long tegra_dc_get_bandwidth(
/* to save power, call when display memory clients would be idle */
static void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
{
+ trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__,
+ dc->emc_clk_rate);
if (tegra_is_clk_enabled(dc->emc_clk))
clk_disable(dc->emc_clk);
dc->emc_clk_rate = 0;
@@ -1007,6 +1068,8 @@ static void tegra_dc_program_bandwidth(struct tegra_dc *dc)
if (w->bandwidth != w->new_bandwidth && w->new_bandwidth != 0)
tegra_dc_set_latency_allowance(dc, w);
+ trace_printk("%s:win%u bandwidth=%d\n", dc->ndev->name, w->idx,
+ w->bandwidth);
}
}
@@ -1030,6 +1093,7 @@ static int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
if (tegra_dc_has_multiple_dc())
new_rate = ULONG_MAX;
+ trace_printk("%s:new_emc_clk_rate=%ld\n", dc->ndev->name, new_rate);
dc->new_emc_clk_rate = new_rate;
return 0;
@@ -1114,14 +1178,6 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
else
tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, DC_CMD_STATE_ACCESS);
- for (i = 0; i < DC_N_WINDOWS; i++) {
- tegra_dc_writel(dc, WINDOW_A_SELECT << i,
- DC_CMD_DISPLAY_WINDOW_HEADER);
- tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
- if (!no_vsync)
- update_mask |= WIN_A_ACT_REQ << i;
- }
-
for (i = 0; i < n; i++) {
struct tegra_dc_win *win = windows[i];
unsigned h_dda;
@@ -1129,12 +1185,13 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
fixed20_12 h_offset, v_offset;
bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
+ bool yuv = tegra_dc_is_yuv(win->fmt);
bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
/* Bytes per pixel of bandwidth, used for dda_inc calculation */
unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1);
- const bool filter_h = win_use_h_filter(win);
- const bool filter_v = win_use_v_filter(win);
+ const bool filter_h = win_use_h_filter(dc, win);
+ const bool filter_v = win_use_v_filter(dc, win);
if (win->z != dc->blend.z[win->idx]) {
dc->blend.z[win->idx] = win->z;
@@ -1158,8 +1215,8 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
continue;
}
- tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH);
- tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
+ tegra_dc_writel(dc, win->fmt & 0x1f, DC_WIN_COLOR_DEPTH);
+ tegra_dc_writel(dc, win->fmt >> 6, DC_WIN_BYTE_SWAP);
tegra_dc_writel(dc,
V_POSITION(win->out_y) | H_POSITION(win->out_x),
@@ -1167,19 +1224,22 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc,
V_SIZE(win->out_h) | H_SIZE(win->out_w),
DC_WIN_SIZE);
- tegra_dc_writel(dc,
- V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
- H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
- DC_WIN_PRESCALED_SIZE);
-
- h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
- v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
- tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
- DC_WIN_DDA_INCREMENT);
- h_dda = compute_initial_dda(win->x);
- v_dda = compute_initial_dda(win->y);
- tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
- tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+
+ if (tegra_dc_feature_has_scaling(dc, win->idx)) {
+ tegra_dc_writel(dc,
+ V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
+ H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
+ DC_WIN_PRESCALED_SIZE);
+
+ h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
+ v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
+ tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
+ DC_WIN_DDA_INCREMENT);
+ h_dda = compute_initial_dda(win->x);
+ v_dda = compute_initial_dda(win->y);
+ tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
+ tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+ }
tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
@@ -1217,19 +1277,21 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc, dfixed_trunc(v_offset),
DC_WINBUF_ADDR_V_OFFSET);
- if (WIN_IS_TILED(win))
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_TILE |
- DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
- DC_WIN_BUFFER_ADDR_MODE);
- else
- tegra_dc_writel(dc,
- DC_WIN_BUFFER_ADDR_MODE_LINEAR |
- DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
- DC_WIN_BUFFER_ADDR_MODE);
+ if (tegra_dc_feature_has_tiling(dc, win->idx)) {
+ if (WIN_IS_TILED(win))
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_TILE |
+ DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
+ else
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR |
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
+ }
val = WIN_ENABLE;
- if (yuvp)
+ if (yuv)
val |= CSC_ENABLE;
else if (tegra_dc_fmt_bpp(win->fmt) < 24)
val |= COLOR_EXPAND;
@@ -1249,6 +1311,14 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ if (win->global_alpha == 255)
+ tegra_dc_writel(dc, 0, DC_WIN_GLOBAL_ALPHA);
+ else
+ tegra_dc_writel(dc, GLOBAL_ALPHA_ENABLE |
+ win->global_alpha, DC_WIN_GLOBAL_ALPHA);
+#endif
+
win->dirty = no_vsync ? 0 : 1;
dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d "
@@ -1259,6 +1329,9 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
dfixed_trunc(win->w), dfixed_trunc(win->h),
win->out_x, win->out_y, win->out_w, win->out_h,
win->fmt, yuvp, Bpp, filter_h, filter_v);
+ trace_printk("%s:win%u in:%ux%u out:%ux%u fmt=%d\n",
+ dc->ndev->name, win->idx, dfixed_trunc(win->w),
+ dfixed_trunc(win->h), win->out_w, win->out_h, win->fmt);
}
if (update_blend) {
@@ -1296,6 +1369,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
update_mask |= NC_HOST_TRIG;
tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
+ trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask);
mutex_unlock(&dc->lock);
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
@@ -1353,6 +1427,7 @@ static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
/* does not support syncing windows on multiple dcs in one call */
int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
{
+ int ret;
if (n < 1 || n > DC_N_WINDOWS)
return -EINVAL;
@@ -1361,13 +1436,18 @@ int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
/* Don't want to timeout on simulator */
- return wait_event_interruptible(windows[0]->dc->wq,
+ ret = wait_event_interruptible(windows[0]->dc->wq,
tegra_dc_windows_are_clean(windows, n));
#else
- return wait_event_interruptible_timeout(windows[0]->dc->wq,
+ trace_printk("%s:Before wait_event_interruptible_timeout\n",
+ windows[0]->dc->ndev->name);
+ ret = wait_event_interruptible_timeout(windows[0]->dc->wq,
tegra_dc_windows_are_clean(windows, n),
HZ);
+ trace_printk("%s:After wait_event_interruptible_timeout\n",
+ windows[0]->dc->ndev->name);
#endif
+ return ret;
}
EXPORT_SYMBOL(tegra_dc_sync_windows);
@@ -1614,6 +1694,7 @@ static bool check_ref_to_sync(struct tegra_dc_mode *mode)
return true;
}
+#ifdef DEBUG
/* return in 1000ths of a Hertz */
static int calc_refresh(const struct tegra_dc_mode *m)
{
@@ -1628,7 +1709,6 @@ static int calc_refresh(const struct tegra_dc_mode *m)
return refresh;
}
-#ifdef DEBUG
static void print_mode(struct tegra_dc *dc,
const struct tegra_dc_mode *mode, const char *note)
{
@@ -1708,6 +1788,7 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
rate = tegra_dc_clk_get_rate(dc);
pclk = tegra_dc_pclk_round_rate(dc, mode->pclk);
+ trace_printk("%s:pclk=%ld\n", dc->ndev->name, pclk);
if (pclk < (mode->pclk / 100 * 99) ||
pclk > (mode->pclk / 100 * 109)) {
dev_err(&dc->ndev->dev,
@@ -1719,6 +1800,7 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
}
div = (rate * 2 / pclk) - 2;
+ trace_printk("%s:div=%ld\n", dc->ndev->name, div);
tegra_dc_writel(dc, 0x00010001,
DC_DISP_SHIFT_CLOCK_OPTIONS);
@@ -1733,18 +1815,14 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ print_mode_info(dc, dc->mode);
return 0;
}
int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dc->mode_lock, flags);
memcpy(&dc->mode, mode, sizeof(dc->mode));
- dc->mode_dirty = true;
- spin_unlock_irqrestore(&dc->mode_lock, flags);
print_mode(dc, mode, __func__);
@@ -1752,46 +1830,6 @@ int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
}
EXPORT_SYMBOL(tegra_dc_set_mode);
-/* convert tegra_dc_mode to fb_videomode
- * return non-zero on error. */
-int tegra_dc_to_fb_videomode(struct fb_videomode *fbmode,
- const struct tegra_dc_mode *mode)
-{
- if (!fbmode || !mode || !mode->pclk)
- return -EINVAL;
-
- memset(fbmode, 0, sizeof(*fbmode));
-
- if (mode->rated_pclk >= 1000)
- fbmode->pixclock = KHZ2PICOS(mode->rated_pclk / 1000);
- else if (mode->pclk >= 1000)
- fbmode->pixclock = KHZ2PICOS(mode->pclk / 1000);
- fbmode->hsync_len = mode->h_sync_width;
- fbmode->vsync_len = mode->v_sync_width;
- fbmode->left_margin = mode->h_back_porch;
- fbmode->upper_margin = mode->v_back_porch;
- fbmode->xres = mode->h_active;
- fbmode->yres = mode->v_active;
- fbmode->right_margin = mode->h_front_porch;
- fbmode->lower_margin = mode->v_front_porch;
- fbmode->vmode = FB_VMODE_NONINTERLACED;
- fbmode->vmode |= mode->stereo_mode ?
-#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
- FB_VMODE_STEREO_FRAME_PACK
-#else
- FB_VMODE_STEREO_LEFT_RIGHT
-#endif
- : 0;
- fbmode->sync |= (mode->flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC) ?
- 0 : FB_SYNC_HOR_HIGH_ACT;
- fbmode->sync |= (mode->flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC) ?
- 0 : FB_SYNC_VERT_HIGH_ACT;
- fbmode->refresh = (calc_refresh(mode) + 500) / 1000;
-
- return 0;
-}
-EXPORT_SYMBOL(tegra_dc_to_fb_videomode);
-
int tegra_dc_set_fb_mode(struct tegra_dc *dc,
const struct fb_videomode *fbmode, bool stereo_mode)
{
@@ -2053,7 +2091,7 @@ u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc)
{
int crc = 0;
- if(!dc) {
+ if (!dc) {
dev_err(&dc->ndev->dev, "Failed to get dc.\n");
goto crc_error;
}
@@ -2133,15 +2171,21 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
int i;
dc->stats.underflows++;
- if (dc->underflow_mask & WIN_A_UF_INT)
+ if (dc->underflow_mask & WIN_A_UF_INT) {
dc->stats.underflows_a += tegra_dc_underflow_count(dc,
DC_WINBUF_AD_UFLOW_STATUS);
- if (dc->underflow_mask & WIN_B_UF_INT)
+ trace_printk("%s:Window A Underflow\n", dc->ndev->name);
+ }
+ if (dc->underflow_mask & WIN_B_UF_INT) {
dc->stats.underflows_b += tegra_dc_underflow_count(dc,
DC_WINBUF_BD_UFLOW_STATUS);
- if (dc->underflow_mask & WIN_C_UF_INT)
+ trace_printk("%s:Window B Underflow\n", dc->ndev->name);
+ }
+ if (dc->underflow_mask & WIN_C_UF_INT) {
dc->stats.underflows_c += tegra_dc_underflow_count(dc,
DC_WINBUF_CD_UFLOW_STATUS);
+ trace_printk("%s:Window C Underflow\n", dc->ndev->name);
+ }
/* Check for any underflow reset conditions */
for (i = 0; i < DC_N_WINDOWS; i++) {
@@ -2153,6 +2197,9 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
schedule_work(&dc->reset_work);
/* reset counter */
dc->windows[i].underflows = 0;
+ trace_printk("%s:Reset work scheduled for "
+ "window %c\n",
+ dc->ndev->name, (65 + i));
}
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -2185,6 +2232,7 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
dc->underflow_mask = 0;
val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
tegra_dc_writel(dc, val | ALL_UF_INT, DC_CMD_INT_MASK);
+ print_underflow_info(dc);
}
#ifndef CONFIG_TEGRA_FPGA_PLATFORM
@@ -2200,18 +2248,6 @@ static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc)
return false;
}
-static void tegra_dc_update_mode(struct tegra_dc *dc)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dc->mode_lock, flags);
- if (dc->mode_dirty) {
- tegra_dc_program_mode(dc, &dc->mode);
- dc->mode_dirty = false;
- }
- spin_unlock_irqrestore(&dc->mode_lock, flags);
-}
-
static void tegra_dc_trigger_windows(struct tegra_dc *dc)
{
u32 val, i;
@@ -2271,9 +2307,6 @@ static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
/* Mark the frame_end as complete. */
if (!completion_done(&dc->frame_end_complete))
complete(&dc->frame_end_complete);
-
- /* handle a mode change, if it was scheduled */
- tegra_dc_update_mode(dc);
}
}
@@ -2298,8 +2331,6 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
if (!completion_done(&dc->frame_end_complete))
complete(&dc->frame_end_complete);
- /* handle a mode change, if it was scheduled */
- tegra_dc_update_mode(dc);
tegra_dc_trigger_windows(dc);
}
}
@@ -2573,6 +2604,7 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
tegra_dc_ext_enable(dc->ext);
+ trace_printk("%s:enable\n", dc->ndev->name);
return true;
}
@@ -2634,14 +2666,40 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
_tegra_dc_controller_disable(dc);
}
+ trace_printk("%s:reset enable\n", dc->ndev->name);
return ret;
}
#endif
+static int _tegra_dc_set_default_videomode(struct tegra_dc *dc)
+{
+ return tegra_dc_set_fb_mode(dc, &tegra_dc_hdmi_fallback_mode, 0);
+}
+
static bool _tegra_dc_enable(struct tegra_dc *dc)
{
- if (dc->mode.pclk == 0)
- return false;
+ if (dc->mode.pclk == 0) {
+ switch (dc->out->type) {
+ case TEGRA_DC_OUT_HDMI:
+ /* DC enable called but no videomode is loaded.
+ Check if HDMI is connected, then set fallback mdoe */
+ if (tegra_dc_hpd(dc)) {
+ if (_tegra_dc_set_default_videomode(dc))
+ return false;
+ } else
+ return false;
+
+ break;
+
+ /* Do nothing for other outputs for now */
+ case TEGRA_DC_OUT_RGB:
+
+ case TEGRA_DC_OUT_DSI:
+
+ default:
+ return false;
+ }
+ }
if (!dc->out)
return false;
@@ -2659,6 +2717,7 @@ void tegra_dc_enable(struct tegra_dc *dc)
dc->enabled = _tegra_dc_enable(dc);
mutex_unlock(&dc->lock);
+ print_mode_info(dc, dc->mode);
}
static void _tegra_dc_controller_disable(struct tegra_dc *dc)
@@ -2691,12 +2750,15 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc)
/* flush any pending syncpt waits */
while (dc->syncpt[i].min < dc->syncpt[i].max) {
+ trace_printk("%s:syncpt flush id=%d\n", dc->ndev->name,
+ dc->syncpt[i].id);
dc->syncpt[i].min++;
nvhost_syncpt_cpu_incr(
&nvhost_get_host(dc->ndev)->syncpt,
dc->syncpt[i].id);
}
}
+ trace_printk("%s:disabled\n", dc->ndev->name);
}
void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable)
@@ -2781,6 +2843,7 @@ void tegra_dc_disable(struct tegra_dc *dc)
mutex_unlock(&dc->lock);
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
mutex_unlock(&dc->one_shot_lock);
+ print_mode_info(dc, dc->mode);
}
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
@@ -2834,6 +2897,7 @@ static void tegra_dc_reset_worker(struct work_struct *work)
unlock:
mutex_unlock(&dc->lock);
mutex_unlock(&shared_lock);
+ trace_printk("%s:reset complete\n", dc->ndev->name);
}
#endif
@@ -2862,7 +2926,8 @@ static ssize_t switch_modeset_print_mode(struct switch_dev *sdev, char *buf)
}
#endif
-static int tegra_dc_probe(struct nvhost_device *ndev)
+static int tegra_dc_probe(struct nvhost_device *ndev,
+ struct nvhost_device_id *id_table)
{
struct tegra_dc *dc;
struct clk *clk;
@@ -2949,12 +3014,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
*/
dc->emc_clk_rate = 0;
- if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
- dc->enabled = true;
-
mutex_init(&dc->lock);
mutex_init(&dc->one_shot_lock);
- spin_lock_init(&dc->mode_lock);
init_completion(&dc->frame_end_complete);
init_waitqueue_head(&dc->wq);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
@@ -2990,6 +3051,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
switch_dev_register(&dc->modeset_switch);
#endif
+ tegra_dc_feature_register(dc);
+
if (dc->pdata->default_out)
tegra_dc_set_out(dc, dc->pdata->default_out);
else
@@ -3004,22 +3067,19 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
dc->ext = NULL;
}
+ mutex_lock(&dc->lock);
+ if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
+ dc->enabled = _tegra_dc_enable(dc);
+ mutex_unlock(&dc->lock);
+
/* interrupt handler must be registered before tegra_fb_register() */
- if (request_irq(irq, tegra_dc_irq, IRQF_DISABLED,
+ if (request_irq(irq, tegra_dc_irq, 0,
dev_name(&ndev->dev), dc)) {
dev_err(&ndev->dev, "request_irq %d failed\n", irq);
ret = -EBUSY;
goto err_put_emc_clk;
}
- /* hack to balance enable_irq calls in _tegra_dc_enable() */
- disable_dc_irq(dc->irq);
-
- mutex_lock(&dc->lock);
- if (dc->enabled)
- _tegra_dc_enable(dc);
- mutex_unlock(&dc->lock);
-
tegra_dc_create_debugfs(dc);
dev_info(&ndev->dev, "probed\n");
@@ -3041,22 +3101,6 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
dc->fb = NULL;
}
- if (dc->out && dc->out->n_modes) {
- struct fb_monspecs specs;
- int i;
-
- memset(&specs, 0, sizeof(specs));
- specs.max_x = dc->mode.h_active * 1000;
- specs.max_y = dc->mode.v_active * 1000;
- specs.modedb_len = dc->out->n_modes;
- specs.modedb = kzalloc(specs.modedb_len *
- sizeof(struct fb_videomode), GFP_KERNEL);
- for (i = 0; i < dc->out->n_modes; i++)
- tegra_dc_to_fb_videomode(&specs.modedb[i],
- &dc->out->modes[i]);
- tegra_fb_update_monspecs(dc->fb, &specs, NULL);
- }
-
if (dc->out && dc->out->hotplug_init)
dc->out->hotplug_init();
@@ -3127,6 +3171,7 @@ static int tegra_dc_suspend(struct nvhost_device *ndev, pm_message_t state)
{
struct tegra_dc *dc = nvhost_get_drvdata(ndev);
+ trace_printk("%s:suspend\n", dc->ndev->name);
dev_info(&ndev->dev, "suspend\n");
tegra_dc_ext_disable(dc->ext);
@@ -3160,6 +3205,7 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
{
struct tegra_dc *dc = nvhost_get_drvdata(ndev);
+ trace_printk("%s:resume\n", dc->ndev->name);
dev_info(&ndev->dev, "resume\n");
mutex_lock(&dc->lock);
diff --git a/drivers/video/tegra/dc/dc_config.c b/drivers/video/tegra/dc/dc_config.c
new file mode 100644
index 00000000..a40712f
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.c
@@ -0,0 +1,246 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ * * Copyright (c) 2012, 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 "dc_config.h"
+
+static struct tegra_dc_feature_entry t20_feature_entries_a[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t20_feature_entries_b[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t20_feature_table_a = {
+ ARRAY_SIZE(t20_feature_entries_a), t20_feature_entries_a,
+};
+
+struct tegra_dc_feature t20_feature_table_b = {
+ ARRAY_SIZE(t20_feature_entries_b), t20_feature_entries_b,
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_a[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_b[] = {
+ { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+ { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+ { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_PREFERRED_FORMATS, {TEGRA_WIN_PREF_FMT_WIN_B,} },
+ { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+ { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+ { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+ { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+ { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+ { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1, 1,} },
+ { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t30_feature_table_a = {
+ ARRAY_SIZE(t30_feature_entries_a), t30_feature_entries_a,
+};
+
+struct tegra_dc_feature t30_feature_table_b = {
+ ARRAY_SIZE(t30_feature_entries_b), t30_feature_entries_b,
+};
+
+int tegra_dc_get_feature(struct tegra_dc_feature *feature, int win_idx,
+ enum tegra_dc_feature_option option)
+{
+ int i;
+ struct tegra_dc_feature_entry *entry;
+
+ if (!feature)
+ return -EINVAL;
+
+ for (i = 0; i < feature->num_entries; i++) {
+ entry = &feature->entries[i];
+ if (entry->window_index == win_idx && entry->option == option)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation)
+{
+ int idx;
+ struct tegra_dc_feature_entry *entry;
+ enum tegra_dc_feature_option option;
+ struct tegra_dc_feature *feature = dc->feature;
+
+ switch (operation) {
+ case GET_WIN_FORMATS:
+ option = TEGRA_DC_FEATURE_FORMATS;
+ break;
+ case GET_WIN_SIZE:
+ option = TEGRA_DC_FEATURE_MAXIMUM_SIZE;
+ break;
+ case HAS_SCALE:
+ option = TEGRA_DC_FEATURE_MAXIMUM_SCALE;
+ break;
+ case HAS_TILED:
+ option = TEGRA_DC_FEATURE_LAYOUT_TYPE;
+ break;
+ case HAS_V_FILTER:
+ option = TEGRA_DC_FEATURE_FILTER_TYPE;
+ break;
+ case HAS_H_FILTER:
+ option = TEGRA_DC_FEATURE_FILTER_TYPE;
+ break;
+ case HAS_GEN2_BLEND:
+ option = TEGRA_DC_FEATURE_BLEND_TYPE;
+ break;
+ default:
+ return NULL;
+ }
+
+ idx = tegra_dc_get_feature(feature, win_idx, option);
+ if (IS_ERR_VALUE(idx))
+ return NULL;
+ entry = &feature->entries[idx];
+
+ return entry->arg;
+}
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx)
+{
+ int i;
+ long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_SCALE);
+
+ for (i = 0; i < ENTRY_SIZE; i++)
+ if (addr[i] != 1)
+ return 1;
+ return 0;
+}
+
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx)
+{
+ long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_TILED);
+
+ return addr[TILED_LAYOUT];
+}
+
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation)
+{
+ long *addr = tegra_dc_parse_feature(dc, win_idx, operation);
+
+ if (operation == HAS_V_FILTER)
+ return addr[V_FILTER];
+ else
+ return addr[H_FILTER];
+}
+
+void tegra_dc_feature_register(struct tegra_dc *dc)
+{
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ if (!dc->ndev->id)
+ dc->feature = &t20_feature_table_a;
+ else
+ dc->feature = &t20_feature_table_b;
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ if (!dc->ndev->id)
+ dc->feature = &t30_feature_table_a;
+ else
+ dc->feature = &t30_feature_table_b;
+#endif
+}
diff --git a/drivers/video/tegra/dc/dc_config.h b/drivers/video/tegra/dc/dc_config.h
new file mode 100644
index 00000000..f513cd0
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.h
@@ -0,0 +1,148 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ * * Copyright (c) 2012, 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 __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+#define __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+
+#include <linux/errno.h>
+#include <mach/dc.h>
+
+#include "dc_priv.h"
+
+#define ENTRY_SIZE 4 /* Size of feature entry args */
+
+/* Define the supported formats. TEGRA_WIN_FMT_WIN_x macros are defined
+ * based on T20/T30 formats. */
+#define TEGRA_WIN_FMT_BASE_CNT (TEGRA_WIN_FMT_YUV422RA + 1)
+#define TEGRA_WIN_FMT_BASE ((1 << TEGRA_WIN_FMT_P8) | \
+ (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+ (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+ (1 << TEGRA_WIN_FMT_B5G6R5) | \
+ (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+ (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+ (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422) | \
+ (1 << TEGRA_WIN_FMT_YUV422) | \
+ (1 << TEGRA_WIN_FMT_YCbCr420P) | \
+ (1 << TEGRA_WIN_FMT_YUV420P) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422P) | \
+ (1 << TEGRA_WIN_FMT_YUV422P) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422R) | \
+ (1 << TEGRA_WIN_FMT_YUV422R))
+
+#define TEGRA_WIN_FMT_WIN_A ((1 << TEGRA_WIN_FMT_P1) | \
+ (1 << TEGRA_WIN_FMT_P2) | \
+ (1 << TEGRA_WIN_FMT_P4) | \
+ (1 << TEGRA_WIN_FMT_P8) | \
+ (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+ (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+ (1 << TEGRA_WIN_FMT_B5G6R5) | \
+ (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+ (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+ (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8))
+
+#define TEGRA_WIN_FMT_WIN_B (TEGRA_WIN_FMT_BASE | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422RA) | \
+ (1 << TEGRA_WIN_FMT_YUV422RA))
+
+#define TEGRA_WIN_FMT_WIN_C (TEGRA_WIN_FMT_BASE | \
+ (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+ (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8) | \
+ (1 << TEGRA_WIN_FMT_YCbCr422RA) | \
+ (1 << TEGRA_WIN_FMT_YUV422RA))
+
+/* preferred formats do not include 32-bpp formats */
+#define TEGRA_WIN_PREF_FMT_WIN_B (TEGRA_WIN_FMT_WIN_B & \
+ ~(1 << TEGRA_WIN_FMT_B8G8R8A8) & \
+ ~(1 << TEGRA_WIN_FMT_R8G8B8A8))
+
+
+
+/* For each entry, we define the offset to read specific feature. Define the
+ * offset for TEGRA_DC_FEATURE_MAXIMUM_SCALE */
+#define H_SCALE_UP 0
+#define V_SCALE_UP 1
+#define H_FILTER_DOWN 2
+#define V_FILTER_DOWN 3
+
+/* Define the offset for TEGRA_DC_FEATURE_MAXIMUM_SIZE */
+#define MAX_WIDTH 0
+#define MIN_WIDTH 1
+#define MAX_HEIGHT 2
+#define MIN_HEIGHT 3
+#define CHECK_SIZE(val, min, max) ( \
+ ((val) < (min) || (val) > (max)) ? -EINVAL : 0)
+
+/* Define the offset for TEGRA_DC_FEATURE_FILTER_TYPE */
+#define V_FILTER 0
+#define H_FILTER 1
+
+/* Define the offset for TEGRA_DC_FEATURE_INVERT_TYPE */
+#define H_INVERT 0
+#define V_INVERT 1
+#define SCAN_COLUMN 2
+
+/* Define the offset for TEGRA_DC_FEATURE_LAYOUT_TYPE. */
+#define PITCHED_LAYOUT 0
+#define TILED_LAYOUT 1
+
+/* Available operations on feature table. */
+enum {
+ HAS_SCALE,
+ HAS_TILED,
+ HAS_V_FILTER,
+ HAS_H_FILTER,
+ HAS_GEN2_BLEND,
+ GET_WIN_FORMATS,
+ GET_WIN_SIZE,
+};
+
+enum tegra_dc_feature_option {
+ TEGRA_DC_FEATURE_FORMATS,
+ TEGRA_DC_FEATURE_BLEND_TYPE,
+ TEGRA_DC_FEATURE_MAXIMUM_SIZE,
+ TEGRA_DC_FEATURE_MAXIMUM_SCALE,
+ TEGRA_DC_FEATURE_FILTER_TYPE,
+ TEGRA_DC_FEATURE_LAYOUT_TYPE,
+ TEGRA_DC_FEATURE_INVERT_TYPE,
+ TEGRA_DC_FEATURE_PREFERRED_FORMATS,
+};
+
+struct tegra_dc_feature_entry {
+ int window_index;
+ enum tegra_dc_feature_option option;
+ long arg[ENTRY_SIZE];
+};
+
+struct tegra_dc_feature {
+ unsigned num_entries;
+ struct tegra_dc_feature_entry *entries;
+};
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation);
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation);
+void tegra_dc_feature_register(struct tegra_dc *dc);
+#endif
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 5cba88f..ce7ac3c 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -4,8 +4,6 @@
* Copyright (C) 2010 Google, Inc.
* Author: Erik Gilling <konkers@android.com>
*
- * Copyright (C) 2010-2012 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.
@@ -23,12 +21,14 @@
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/wait.h>
+#include <linux/fb.h>
#include <linux/completion.h>
#include <linux/switch.h>
#include <mach/dc.h>
#include "../host/dev.h"
+#include "../host/nvhost_acm.h"
#include "../host/host1x/host1x_syncpt.h"
#include <mach/tegra_dc_ext.h>
@@ -65,11 +65,13 @@ struct tegra_dc_out_ops {
void (*enable)(struct tegra_dc *dc);
/* disable output. dc clocks are on at this point */
void (*disable)(struct tegra_dc *dc);
-
/* suspend output. dc clocks are on at this point */
void (*suspend)(struct tegra_dc *dc);
/* resume output. dc clocks are on at this point */
void (*resume)(struct tegra_dc *dc);
+ /* mode filter. to provide a list of supported modes*/
+ bool (*mode_filter)(const struct tegra_dc *dc,
+ struct fb_videomode *mode);
};
struct tegra_dc {
@@ -95,8 +97,6 @@ struct tegra_dc {
void *out_data;
struct tegra_dc_mode mode;
- bool mode_dirty;
- spinlock_t mode_lock;
struct tegra_dc_win windows[DC_N_WINDOWS];
struct tegra_dc_blend blend;
@@ -137,6 +137,8 @@ struct tegra_dc {
struct tegra_dc_ext *ext;
+ struct tegra_dc_feature *feature;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugdir;
#endif
@@ -159,14 +161,19 @@ static inline void tegra_dc_io_end(struct tegra_dc *dc)
static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
unsigned long reg)
{
+ unsigned long ret;
+
BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
- return readl(dc->base + reg * 4);
+ ret = readl(dc->base + reg * 4);
+ trace_printk("readl %p=%#08lx\n", dc->base + reg * 4, ret);
+ return ret;
}
static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val,
unsigned long reg)
{
BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
+ trace_printk("writel %p=%#08lx\n", dc->base + reg * 4, val);
writel(val, dc->base + reg * 4);
}
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
index 2b8f8be..ded64de 100644
--- a/drivers/video/tegra/dc/dc_reg.h
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -460,6 +460,12 @@
#define DC_WIN_HP_FETCH_CONTROL 0x714
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+#define DC_WIN_GLOBAL_ALPHA 0x715
+#define GLOBAL_ALPHA_ENABLE 0x10000
+#endif
+
#define DC_WINBUF_START_ADDR 0x800
#define DC_WINBUF_START_ADDR_NS 0x801
#define DC_WINBUF_START_ADDR_U 0x802
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index c33d6e0..69cc60f 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -24,6 +24,8 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <mach/clk.h>
#include <mach/dc.h>
@@ -107,6 +109,7 @@ struct tegra_dc_dsi_data {
struct clk *dc_clk;
struct clk *dsi_clk;
+ struct clk *dsi_fixed_clk;
bool clk_ref;
struct mutex lock;
@@ -287,18 +290,128 @@ const u32 init_reg[] = {
inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg)
{
+ unsigned long ret;
+
BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
- return readl(dsi->base + reg * 4);
+ ret = readl(dsi->base + reg * 4);
+ trace_printk("readl %p=%#08lx\n", dsi->base + reg * 4, ret);
+ return ret;
}
EXPORT_SYMBOL(tegra_dsi_readl);
inline void tegra_dsi_writel(struct tegra_dc_dsi_data *dsi, u32 val, u32 reg)
{
BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
+ trace_printk("writel %p=%#08x\n", dsi->base + reg * 4, val);
writel(val, dsi->base + reg * 4);
}
EXPORT_SYMBOL(tegra_dsi_writel);
+#ifdef CONFIG_DEBUG_FS
+static int dbg_dsi_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc_dsi_data *dsi = s->private;
+
+#define DUMP_REG(a) do { \
+ seq_printf(s, "%-32s\t%03x\t%08lx\n", \
+ #a, a, tegra_dsi_readl(dsi, a)); \
+ } while (0)
+
+ tegra_dc_io_start(dsi->dc);
+ clk_enable(dsi->dsi_clk);
+
+ DUMP_REG(DSI_INCR_SYNCPT_CNTRL);
+ DUMP_REG(DSI_INCR_SYNCPT_ERROR);
+ DUMP_REG(DSI_CTXSW);
+ DUMP_REG(DSI_POWER_CONTROL);
+ DUMP_REG(DSI_INT_ENABLE);
+ DUMP_REG(DSI_CONTROL);
+ DUMP_REG(DSI_SOL_DELAY);
+ DUMP_REG(DSI_MAX_THRESHOLD);
+ DUMP_REG(DSI_TRIGGER);
+ DUMP_REG(DSI_TX_CRC);
+ DUMP_REG(DSI_STATUS);
+ DUMP_REG(DSI_INIT_SEQ_CONTROL);
+ DUMP_REG(DSI_INIT_SEQ_DATA_0);
+ DUMP_REG(DSI_INIT_SEQ_DATA_1);
+ DUMP_REG(DSI_INIT_SEQ_DATA_2);
+ DUMP_REG(DSI_INIT_SEQ_DATA_3);
+ DUMP_REG(DSI_INIT_SEQ_DATA_4);
+ DUMP_REG(DSI_INIT_SEQ_DATA_5);
+ DUMP_REG(DSI_INIT_SEQ_DATA_6);
+ DUMP_REG(DSI_INIT_SEQ_DATA_7);
+ DUMP_REG(DSI_PKT_SEQ_0_LO);
+ DUMP_REG(DSI_PKT_SEQ_0_HI);
+ DUMP_REG(DSI_PKT_SEQ_1_LO);
+ DUMP_REG(DSI_PKT_SEQ_1_HI);
+ DUMP_REG(DSI_PKT_SEQ_2_LO);
+ DUMP_REG(DSI_PKT_SEQ_2_HI);
+ DUMP_REG(DSI_PKT_SEQ_3_LO);
+ DUMP_REG(DSI_PKT_SEQ_3_HI);
+ DUMP_REG(DSI_PKT_SEQ_4_LO);
+ DUMP_REG(DSI_PKT_SEQ_4_HI);
+ DUMP_REG(DSI_PKT_SEQ_5_LO);
+ DUMP_REG(DSI_PKT_SEQ_5_HI);
+ DUMP_REG(DSI_DCS_CMDS);
+ DUMP_REG(DSI_PKT_LEN_0_1);
+ DUMP_REG(DSI_PKT_LEN_2_3);
+ DUMP_REG(DSI_PKT_LEN_4_5);
+ DUMP_REG(DSI_PKT_LEN_6_7);
+ DUMP_REG(DSI_PHY_TIMING_0);
+ DUMP_REG(DSI_PHY_TIMING_1);
+ DUMP_REG(DSI_PHY_TIMING_2);
+ DUMP_REG(DSI_BTA_TIMING);
+ DUMP_REG(DSI_TIMEOUT_0);
+ DUMP_REG(DSI_TIMEOUT_1);
+ DUMP_REG(DSI_TO_TALLY);
+ DUMP_REG(DSI_PAD_CONTROL);
+ DUMP_REG(DSI_PAD_CONTROL_CD);
+ DUMP_REG(DSI_PAD_CD_STATUS);
+ DUMP_REG(DSI_VID_MODE_CONTROL);
+#undef DUMP_REG
+
+ clk_disable(dsi->dsi_clk);
+ tegra_dc_io_end(dsi->dc);
+
+ return 0;
+}
+
+static int dbg_dsi_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_dsi_show, inode->i_private);
+}
+
+static const struct file_operations dbg_fops = {
+ .open = dbg_dsi_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *dsidir;
+
+static void tegra_dc_dsi_debug_create(struct tegra_dc_dsi_data *dsi)
+{
+ struct dentry *retval;
+
+ dsidir = debugfs_create_dir("tegra_dsi", NULL);
+ if (!dsidir)
+ return;
+ retval = debugfs_create_file("regs", S_IRUGO, dsidir, dsi,
+ &dbg_fops);
+ if (!retval)
+ goto free_out;
+ return;
+free_out:
+ debugfs_remove_recursive(dsidir);
+ dsidir = NULL;
+ return;
+}
+#else
+static inline void tegra_dc_dsi_debug_create(struct tegra_dc_dsi_data *dsi)
+{ }
+#endif
+
static int tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi)
{
u32 val;
@@ -1341,6 +1454,7 @@ static void tegra_dsi_set_dsi_clk(struct tegra_dc *dc,
if (!dsi->clk_ref) {
dsi->clk_ref = true;
clk_enable(dsi->dsi_clk);
+ clk_enable(dsi->dsi_fixed_clk);
tegra_periph_reset_deassert(dsi->dsi_clk);
}
dsi->current_dsi_clk_khz = clk_get_rate(dsi->dsi_clk) / 1000;
@@ -1817,6 +1931,10 @@ static struct dsi_status *tegra_dsi_prepare_host_transmission(
if (tegra_dsi_host_busy(dsi)) {
tegra_dsi_soft_reset(dsi);
+
+ /* WAR to stop host write in middle */
+ tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_TRIGGER);
+
if (tegra_dsi_host_busy(dsi)) {
err = -EBUSY;
dev_err(&dc->ndev->dev, "DSI host busy\n");
@@ -2584,6 +2702,7 @@ static void _tegra_dc_dsi_init(struct tegra_dc *dc)
{
struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+ tegra_dc_dsi_debug_create(dsi);
tegra_dsi_init_sw(dc, dsi);
/* TODO: Configure the CSI pad configuration */
}
@@ -2748,6 +2867,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
void __iomem *base;
struct clk *dc_clk = NULL;
struct clk *dsi_clk = NULL;
+ struct clk *dsi_fixed_clk = NULL;
struct tegra_dsi_out *dsi_pdata;
int err;
@@ -2790,8 +2910,9 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
dsi_clk = clk_get(&dc->ndev->dev, "dsib");
else
dsi_clk = clk_get(&dc->ndev->dev, "dsia");
+ dsi_fixed_clk = clk_get(&dc->ndev->dev, "dsi-fixed");
- if (IS_ERR_OR_NULL(dsi_clk)) {
+ if (IS_ERR_OR_NULL(dsi_clk) || IS_ERR_OR_NULL(dsi_fixed_clk)) {
dev_err(&dc->ndev->dev, "dsi: can't get clock\n");
err = -EBUSY;
goto err_release_regs;
@@ -2811,6 +2932,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
dsi->base_res = base_res;
dsi->dc_clk = dc_clk;
dsi->dsi_clk = dsi_clk;
+ dsi->dsi_fixed_clk = dsi_fixed_clk;
err = tegra_dc_dsi_cp_info(dsi, dsi_pdata);
if (err < 0)
@@ -2824,6 +2946,7 @@ static int tegra_dc_dsi_init(struct tegra_dc *dc)
err_dsi_data:
err_clk_put:
clk_put(dsi_clk);
+ clk_put(dsi_fixed_clk);
err_release_regs:
release_resource(base_res);
err_free_dsi:
@@ -2937,6 +3060,7 @@ static int tegra_dsi_deep_sleep(struct tegra_dc *dc,
/* Disable dsi source clock */
clk_disable(dsi->dsi_clk);
+ clk_disable(dsi->dsi_fixed_clk);
dsi->clk_ref = false;
dsi->enabled = false;
diff --git a/drivers/video/tegra/dc/ext/Makefile b/drivers/video/tegra/dc/ext/Makefile
index 19860ab..343217c 100644
--- a/drivers/video/tegra/dc/ext/Makefile
+++ b/drivers/video/tegra/dc/ext/Makefile
@@ -1,3 +1,4 @@
+GCOV_PROFILE := y
obj-y += dev.o
obj-y += util.o
obj-y += cursor.o
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 04553e7..c349a47 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -27,11 +27,12 @@
#include <video/tegra_dc_ext.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/tegra_dc_ext.h>
/* XXX ew */
#include "../dc_priv.h"
+#include "../dc_config.h"
/* XXX ew 2 */
#include "../../host/dev.h"
/* XXX ew 3 */
@@ -172,10 +173,39 @@ void tegra_dc_ext_disable(struct tegra_dc_ext *ext)
}
}
+int tegra_dc_ext_check_windowattr(struct tegra_dc_ext *ext,
+ struct tegra_dc_win *win)
+{
+ long *addr;
+ struct tegra_dc *dc = ext->dc;
+
+ /* Check the window format */
+ addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_FORMATS);
+ if (!test_bit(win->fmt, addr)) {
+ dev_err(&dc->ndev->dev, "Color format of window %d is"
+ " invalid.\n", win->idx);
+ goto fail;
+ }
+
+ /* Check window size */
+ addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_SIZE);
+ if (CHECK_SIZE(win->out_w, addr[MIN_WIDTH], addr[MAX_WIDTH]) ||
+ CHECK_SIZE(win->out_h, addr[MIN_HEIGHT], addr[MAX_HEIGHT])) {
+ dev_err(&dc->ndev->dev, "Size of window %d is"
+ " invalid.\n", win->idx);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
struct tegra_dc_win *win,
const struct tegra_dc_ext_flip_win *flip_win)
{
+ int err = 0;
struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
if (flip_win->handle[TEGRA_DC_Y] == NULL) {
@@ -195,6 +225,10 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
win->flags |= TEGRA_WIN_FLAG_INVERT_H;
if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_V)
win->flags |= TEGRA_WIN_FLAG_INVERT_V;
+ if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA)
+ win->global_alpha = flip_win->attr.global_alpha;
+ else
+ win->global_alpha = 255;
win->fmt = flip_win->attr.pixformat;
win->x.full = flip_win->attr.x;
win->y.full = flip_win->attr.y;
@@ -223,6 +257,11 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
win->stride = flip_win->attr.stride;
win->stride_uv = flip_win->attr.stride_uv;
+ err = tegra_dc_ext_check_windowattr(ext, win);
+ if (err < 0)
+ dev_err(&ext->dc->ndev->dev,
+ "Window atrributes are invalid.\n");
+
if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
nvhost_syncpt_wait_timeout(
&nvhost_get_host(ext->dc->ndev)->syncpt,
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index 95a637d..2a0c549 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -25,7 +25,7 @@
#include <linux/poll.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <video/tegra_dc_ext.h>
diff --git a/drivers/video/tegra/dc/ext/util.c b/drivers/video/tegra/dc/ext/util.c
index 7470855..cede642 100644
--- a/drivers/video/tegra/dc/ext/util.c
+++ b/drivers/video/tegra/dc/ext/util.c
@@ -20,7 +20,7 @@
#include <linux/types.h>
#include <mach/dc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
/* ugh */
#include "../../nvmap/nvmap.h"
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index 2e1df8d..59b9afc 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -67,6 +67,28 @@
#define HDMI_ELD_PRODUCT_CODE_INDEX 18
#define HDMI_ELD_MONITOR_NAME_INDEX 20
+/* These two values need to be cross checked in case of
+ addition/removal from tegra_dc_hdmi_aspect_ratios[] */
+#define TEGRA_DC_HDMI_MIN_ASPECT_RATIO_PERCENT 80
+#define TEGRA_DC_HDMI_MAX_ASPECT_RATIO_PERCENT 320
+
+/* Percentage equivalent of standard aspect ratios
+ accurate upto two decimal digits */
+static int tegra_dc_hdmi_aspect_ratios[] = {
+ /* 3:2 */ 150,
+ /* 4:3 */ 133,
+ /* 4:5 */ 80,
+ /* 5:4 */ 125,
+ /* 9:5 */ 180,
+ /* 16:5 */ 320,
+ /* 16:9 */ 178,
+ /* 16:10 */ 160,
+ /* 19:10 */ 190,
+ /* 25:16 */ 156,
+ /* 64:35 */ 183,
+ /* 72:35 */ 206
+};
+
struct tegra_dc_hdmi_data {
struct tegra_dc *dc;
struct tegra_edid *edid;
@@ -94,6 +116,7 @@ struct tegra_dc_hdmi_data {
bool clk_enabled;
unsigned audio_freq;
unsigned audio_source;
+ bool audio_inject_null;
bool dvi;
};
@@ -947,12 +970,16 @@ static const struct tegra_hdmi_audio_config
unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi,
unsigned long reg)
{
- return readl(hdmi->base + reg * 4);
+ unsigned long ret;
+ ret = readl(hdmi->base + reg * 4);
+ trace_printk("readl %p=%#08lx\n", hdmi->base + reg * 4, ret);
+ return ret;
}
void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi,
unsigned long val, unsigned long reg)
{
+ trace_printk("writel %p=%#08lx\n", hdmi->base + reg * 4, val);
writel(val, hdmi->base + reg * 4);
}
@@ -1240,62 +1267,84 @@ static bool tegra_dc_reload_mode(struct fb_videomode *mode)
return false;
}
+static bool tegra_dc_hdmi_valid_asp_ratio(const struct tegra_dc *dc,
+ struct fb_videomode *mode)
+{
+ int count = 0;
+ int m_aspratio = 0;
+ int s_aspratio = 0;
+
+ /* To check the aspect upto two decimal digits, calculate in % */
+ m_aspratio = (mode->xres*100 / mode->yres);
+
+ if ((m_aspratio < TEGRA_DC_HDMI_MIN_ASPECT_RATIO_PERCENT) ||
+ (m_aspratio > TEGRA_DC_HDMI_MAX_ASPECT_RATIO_PERCENT))
+ return false;
+
+ /* Check from the table of supported aspect ratios, allow
+ difference of 1% for second decimal digit calibration */
+ for (count = 0; count < ARRAY_SIZE(tegra_dc_hdmi_aspect_ratios);
+ count++) {
+ s_aspratio = tegra_dc_hdmi_aspect_ratios[count];
+ if ((m_aspratio == s_aspratio) ||
+ (abs(m_aspratio - s_aspratio) == 1))
+ return true;
+ }
+
+ return false;
+}
+
static bool tegra_dc_hdmi_mode_filter(const struct tegra_dc *dc,
struct fb_videomode *mode)
{
- int i;
- int clock_per_frame;
+ if (mode->vmode & FB_VMODE_INTERLACED)
+ return false;
+ /* Ignore modes with a 0 pixel clock */
if (!mode->pixclock)
return false;
#ifdef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
- if (PICOS2KHZ(mode->pixclock) > 74250)
- return false;
+ if (PICOS2KHZ(mode->pixclock) > 74250)
+ return false;
#endif
- for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_modes); i++) {
- const struct fb_videomode *supported_mode
- = &tegra_dc_hdmi_supported_modes[i];
- if (tegra_dc_hdmi_mode_equal(supported_mode, mode) &&
- tegra_dc_hdmi_valid_pixclock(dc, supported_mode)) {
- if (mode->lower_margin == 1) {
- /* This might be the case for HDMI<->DVI
- * where std VESA representation will not
- * pass constraint V_FRONT_PORCH >=
- * V_REF_TO_SYNC + 1.So reload mode in
- * CVT timing standards.
- */
- if (!tegra_dc_reload_mode(mode))
- return false;
- }
- else
- memcpy(mode, supported_mode, sizeof(*mode));
+ /* Check if the mode's pixel clock is more than the max rate*/
+ if (!tegra_dc_hdmi_valid_pixclock(dc, mode))
+ return false;
- mode->flag = FB_MODE_IS_DETAILED;
- clock_per_frame = tegra_dc_calc_clock_per_frame(mode);
- mode->refresh = (PICOS2KHZ(mode->pixclock) * 1000)
- / clock_per_frame;
- return true;
+ /* Check if the mode's aspect ratio is supported */
+ if (!tegra_dc_hdmi_valid_asp_ratio(dc, mode))
+ return false;
+
+ /* Check some of DC's constraints */
+ if (mode->hsync_len > 1 && mode->vsync_len > 1 &&
+ mode->lower_margin + mode->vsync_len + mode->upper_margin > 1 &&
+ mode->xres >= 16 && mode->yres >= 16) {
+
+ if (mode->lower_margin == 1) {
+ /* This might be the case for HDMI<->DVI
+ * where std VESA representation will not
+ * pass constraint V_FRONT_PORCH >=
+ * V_REF_TO_SYNC + 1.So reload mode in
+ * CVT timing standards.
+ */
+ if (!tegra_dc_reload_mode(mode))
+ return false;
}
+ mode->flag = FB_MODE_IS_DETAILED;
+ mode->refresh = (PICOS2KHZ(mode->pixclock) * 1000) /
+ tegra_dc_calc_clock_per_frame(mode);
+ return true;
}
return false;
}
-
static bool tegra_dc_hdmi_hpd(struct tegra_dc *dc)
{
- int sense;
- int level;
-
- level = gpio_get_value(dc->out->hotplug_gpio);
-
- sense = dc->out->flags & TEGRA_DC_OUT_HOTPLUG_MASK;
-
- return (sense == TEGRA_DC_OUT_HOTPLUG_HIGH && level) ||
- (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level);
+ return tegra_dc_hpd(dc);
}
@@ -1816,7 +1865,10 @@ static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc, unsigned audio_freq,
a_source = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF;
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
- tegra_hdmi_writel(hdmi,a_source | AUDIO_CNTRL0_INJECT_NULLSMPL,
+ if (hdmi->audio_inject_null)
+ a_source |= AUDIO_CNTRL0_INJECT_NULLSMPL;
+
+ tegra_hdmi_writel(hdmi,a_source,
HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0);
tegra_hdmi_writel(hdmi,
AUDIO_CNTRL0_ERROR_TOLERANCE(6) |
@@ -1919,6 +1971,31 @@ int tegra_hdmi_setup_audio_freq_source(unsigned audio_freq, unsigned audio_sourc
EXPORT_SYMBOL(tegra_hdmi_setup_audio_freq_source);
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+int tegra_hdmi_audio_null_sample_inject(bool on)
+{
+ struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
+ unsigned int val = 0;
+
+ if (!hdmi)
+ return -EAGAIN;
+
+ if (hdmi->audio_inject_null != on) {
+ hdmi->audio_inject_null = on;
+ if (hdmi->clk_enabled) {
+ val = tegra_hdmi_readl(hdmi,
+ HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0);
+ val &= ~AUDIO_CNTRL0_INJECT_NULLSMPL;
+ if (on)
+ val |= AUDIO_CNTRL0_INJECT_NULLSMPL;
+ tegra_hdmi_writel(hdmi,val,
+ HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_hdmi_audio_null_sample_inject);
+
int tegra_hdmi_setup_hda_presence()
{
struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
@@ -2005,6 +2082,11 @@ static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi)
avi.r = HDMI_AVI_R_SAME;
+ if ((dc->mode.h_active == 720) && ((dc->mode.v_active == 480) || (dc->mode.v_active == 576)))
+ tegra_dc_writel(dc, 0x00101010, DC_DISP_BORDER_COLOR);
+ else
+ tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
+
if (dc->mode.v_active == 480) {
if (dc->mode.h_active == 640) {
avi.m = HDMI_AVI_M_4_3;
@@ -2037,9 +2119,12 @@ static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi)
(dc->mode.v_active == 2205 && dc->mode.stereo_mode)) {
/* VIC for both 1080p and 1080p 3D mode */
avi.m = HDMI_AVI_M_16_9;
- if (dc->mode.h_front_porch == 88)
- avi.vic = 16; /* 60 Hz */
- else if (dc->mode.h_front_porch == 528)
+ if (dc->mode.h_front_porch == 88) {
+ if (dc->mode.pclk > 74250000)
+ avi.vic = 16; /* 60 Hz */
+ else
+ avi.vic = 34; /* 30 Hz */
+ } else if (dc->mode.h_front_porch == 528)
avi.vic = 31; /* 50 Hz */
else
avi.vic = 32; /* 24 Hz */
@@ -2200,10 +2285,16 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
VSYNC_WINDOW_ENABLE,
HDMI_NV_PDISP_HDMI_VSYNC_WINDOW);
- tegra_hdmi_writel(hdmi,
- (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
- ARM_VIDEO_RANGE_LIMITED,
- HDMI_NV_PDISP_INPUT_CONTROL);
+ if ((dc->mode.h_active == 720) && ((dc->mode.v_active == 480) || (dc->mode.v_active == 576)))
+ tegra_hdmi_writel(hdmi,
+ (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
+ ARM_VIDEO_RANGE_FULL,
+ HDMI_NV_PDISP_INPUT_CONTROL);
+ else
+ tegra_hdmi_writel(hdmi,
+ (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
+ ARM_VIDEO_RANGE_LIMITED,
+ HDMI_NV_PDISP_INPUT_CONTROL);
clk_disable(hdmi->disp1_clk);
clk_disable(hdmi->disp2_clk);
@@ -2374,6 +2465,7 @@ struct tegra_dc_out_ops tegra_dc_hdmi_ops = {
.detect = tegra_dc_hdmi_detect,
.suspend = tegra_dc_hdmi_suspend,
.resume = tegra_dc_hdmi_resume,
+ .mode_filter = tegra_dc_hdmi_mode_filter,
};
struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc)
diff --git a/drivers/video/tegra/dc/rgb.c b/drivers/video/tegra/dc/rgb.c
index 2112643..47d4e69 100644
--- a/drivers/video/tegra/dc/rgb.c
+++ b/drivers/video/tegra/dc/rgb.c
@@ -90,7 +90,7 @@ static const u32 tegra_dc_rgb_disable_pintable[] = {
DC_COM_PIN_OUTPUT_SELECT6, 0x00000000,
};
-void tegra_dc_rgb_enable(struct tegra_dc *dc)
+static void tegra_dc_rgb_enable(struct tegra_dc *dc)
{
int i;
u32 out_sel_pintable[ARRAY_SIZE(tegra_dc_rgb_enable_out_sel_pintable)];
@@ -144,9 +144,13 @@ void tegra_dc_rgb_enable(struct tegra_dc *dc)
}
tegra_dc_write_table(dc, out_sel_pintable);
+
+ /* Inform DC register updated */
+ tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
}
-void tegra_dc_rgb_disable(struct tegra_dc *dc)
+static void tegra_dc_rgb_disable(struct tegra_dc *dc)
{
tegra_dc_writel(dc, 0x00000000, DC_CMD_DISPLAY_POWER_CONTROL);
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index e24588b..50aa9b3 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -6,7 +6,7 @@
* Colin Cross <ccross@android.com>
* Travis Geiselbrecht <travis@palm.com>
*
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (C) 2010-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
@@ -37,7 +37,7 @@
#include <mach/dc.h>
#include <mach/fb.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "host/dev.h"
#include "nvmap/nvmap.h"
@@ -64,11 +64,27 @@ static u32 pseudo_palette[16];
static int tegra_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
+ struct tegra_fb_info *tegra_fb = info->par;
+ struct tegra_dc *dc = tegra_fb->win->dc;
+ struct tegra_dc_out_ops *ops = dc->out_ops;
+ struct fb_videomode mode;
+
if ((var->yres * var->xres * var->bits_per_pixel / 8 * 2) >
info->screen_size)
return -EINVAL;
- /* double yres_virtual to allow double buffering through pan_display */
+ /* Apply mode filter for HDMI only -LVDS supports only fix mode */
+ if (ops && ops->mode_filter) {
+
+ fb_var_to_videomode(&mode, var);
+ if (!ops->mode_filter(dc, &mode))
+ return -EINVAL;
+
+ /* Mode filter may have modified the mode */
+ fb_videomode_to_var(var, &mode);
+ }
+
+ /* Double yres_virtual to allow double buffering through pan_display */
var->yres_virtual = var->yres * 2;
return 0;
@@ -79,10 +95,6 @@ static int tegra_fb_set_par(struct fb_info *info)
struct tegra_fb_info *tegra_fb = info->par;
struct fb_var_screeninfo *var = &info->var;
- BUG_ON(info == NULL);
- if (!info)
- return -EINVAL;
-
if (var->bits_per_pixel) {
/* we only support RGB ordering for now */
switch (var->bits_per_pixel) {
@@ -287,16 +299,6 @@ static int tegra_fb_blank(int blank, struct fb_info *info)
dev_dbg(&tegra_fb->ndev->dev, "unblank\n");
tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
tegra_dc_enable(tegra_fb->win->dc);
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
- /*
- * TODO:
- * This is a work around to provide an unblanking flip
- * to dc driver, required to display fb-console after
- * a blank event,and needs to be replaced by a proper
- * unblanking mechanism
- */
- tegra_fb_flip_win(tegra_fb);
-#endif
return 0;
case FB_BLANK_NORMAL:
@@ -335,7 +337,8 @@ static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
(var->xoffset * (var->bits_per_pixel/8));
tegra_fb->win->phys_addr = addr;
- /* TODO: update virt_addr */
+ tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
+ tegra_fb->win->virt_addr = info->screen_base;
tegra_dc_update_windows(&tegra_fb->win, 1);
tegra_dc_sync_windows(&tegra_fb->win, 1);
@@ -524,7 +527,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
unsigned long fb_size = 0;
unsigned long fb_phys = 0;
int ret = 0;
- struct fb_videomode m;
win = tegra_dc_get_window(dc, fb_data->win);
if (!win) {
@@ -576,15 +578,22 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->fix.line_length = round_up(info->fix.line_length,
TEGRA_LINEAR_PITCH_ALIGNMENT);
- INIT_LIST_HEAD(&info->modelist);
- tegra_dc_to_fb_videomode(&m, &dc->mode);
- fb_videomode_to_var(&info->var, &m);
+ info->var.xres = fb_data->xres;
+ info->var.yres = fb_data->yres;
info->var.xres_virtual = fb_data->xres;
info->var.yres_virtual = fb_data->yres * 2;
info->var.bits_per_pixel = fb_data->bits_per_pixel;
info->var.activate = FB_ACTIVATE_VBL;
info->var.height = tegra_dc_get_out_height(dc);
info->var.width = tegra_dc_get_out_width(dc);
+ info->var.pixclock = 0;
+ info->var.left_margin = 0;
+ info->var.right_margin = 0;
+ info->var.upper_margin = 0;
+ info->var.lower_margin = 0;
+ info->var.hsync_len = 0;
+ info->var.vsync_len = 0;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
win->x.full = dfixed_const(0);
win->y.full = dfixed_const(0);
diff --git a/drivers/video/tegra/host/Makefile b/drivers/video/tegra/host/Makefile
index 0180885..d47c975 100644
--- a/drivers/video/tegra/host/Makefile
+++ b/drivers/video/tegra/host/Makefile
@@ -9,7 +9,8 @@ nvhost-objs = \
bus.o \
dev.o \
debug.o \
- bus_client.o
+ bus_client.o \
+ chip_support.o
obj-$(CONFIG_TEGRA_GRHOST) += mpe/
obj-$(CONFIG_TEGRA_GRHOST) += gr3d/
diff --git a/drivers/video/tegra/host/bus.c b/drivers/video/tegra/host/bus.c
index 774aac7..e59dc41 100644
--- a/drivers/video/tegra/host/bus.c
+++ b/drivers/video/tegra/host/bus.c
@@ -17,11 +17,14 @@
*
*/
+#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/nvhost.h>
+#include "bus.h"
#include "dev.h"
+struct nvhost_bus *nvhost_bus_inst;
struct nvhost_master *nvhost;
struct resource *nvhost_get_resource(struct nvhost_device *dev,
@@ -72,12 +75,42 @@ int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
}
EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
+static struct nvhost_device_id *nvhost_bus_match_id(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
+{
+ while (id_table->name[0]) {
+ if (strcmp(dev->name, id_table->name) == 0)
+ return id_table;
+ id_table++;
+ }
+ return NULL;
+}
+
+static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
+{
+ struct nvhost_device *dev = to_nvhost_device(_dev);
+ struct nvhost_driver *ndrv = to_nvhost_driver(drv);
+
+ /* check if driver support multiple devices through id_table */
+ if (ndrv->id_table)
+ return nvhost_bus_match_id(dev, ndrv->id_table) != NULL;
+ else /* driver does not support id_table */
+ return !strncmp(dev->name, drv->name, strlen(drv->name));
+}
+
static int nvhost_drv_probe(struct device *_dev)
{
struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
struct nvhost_device *dev = to_nvhost_device(_dev);
- return drv->probe(dev);
+ if (drv && drv->probe) {
+ if (drv->id_table)
+ return drv->probe(dev, nvhost_bus_match_id(dev, drv->id_table));
+ else
+ return drv->probe(dev, NULL);
+ }
+ else
+ return -ENODEV;
}
static int nvhost_drv_remove(struct device *_dev)
@@ -98,7 +131,7 @@ static void nvhost_drv_shutdown(struct device *_dev)
int nvhost_driver_register(struct nvhost_driver *drv)
{
- drv->driver.bus = &nvhost_bus_type;
+ drv->driver.bus = &nvhost_bus_inst->nvhost_bus_type;
if (drv->probe)
drv->driver.probe = nvhost_drv_probe;
if (drv->remove)
@@ -129,7 +162,7 @@ int nvhost_device_register(struct nvhost_device *dev)
if (!dev->dev.parent && nvhost && nvhost->dev != dev)
dev->dev.parent = &nvhost->dev->dev;
- dev->dev.bus = &nvhost_bus_type;
+ dev->dev.bus = &nvhost_bus_inst->nvhost_bus_type;
if (dev->id != -1)
dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
@@ -194,13 +227,6 @@ void nvhost_device_unregister(struct nvhost_device *dev)
}
EXPORT_SYMBOL_GPL(nvhost_device_unregister);
-static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
-{
- struct nvhost_device *dev = to_nvhost_device(_dev);
-
- return !strncmp(dev->name, drv->name, strlen(drv->name));
-}
-
#ifdef CONFIG_PM_SLEEP
static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
@@ -528,13 +554,6 @@ static const struct dev_pm_ops nvhost_dev_pm_ops = {
.runtime_idle = nvhost_pm_runtime_idle,
};
-struct bus_type nvhost_bus_type = {
- .name = "nvhost",
- .match = nvhost_bus_match,
- .pm = &nvhost_dev_pm_ops,
-};
-EXPORT_SYMBOL(nvhost_bus_type);
-
static int set_parent(struct device *dev, void *data)
{
struct nvhost_device *ndev = to_nvhost_device(dev);
@@ -549,21 +568,44 @@ int nvhost_bus_add_host(struct nvhost_master *host)
nvhost = host;
/* Assign host1x as parent to all devices in nvhost bus */
- bus_for_each_dev(&nvhost_bus_type, NULL, host, set_parent);
+ bus_for_each_dev(&nvhost_bus_inst->nvhost_bus_type, NULL, host, set_parent);
return 0;
}
+struct nvhost_bus *nvhost_bus_get(void)
+{
+ return nvhost_bus_inst;
+}
int nvhost_bus_init(void)
{
int err;
+ struct nvhost_chip_support *chip_ops;
pr_info("host1x bus init\n");
- err = bus_register(&nvhost_bus_type);
+ nvhost_bus_inst = kzalloc(sizeof(*nvhost_bus_inst), GFP_KERNEL);
+ if (nvhost_bus_inst == NULL) {
+ pr_err("%s: Cannot allocate nvhost_bus\n", __func__);
+ return -ENOMEM;
+ }
+
+ chip_ops = kzalloc(sizeof(*chip_ops), GFP_KERNEL);
+ if (chip_ops == NULL) {
+ pr_err("%s: Cannot allocate nvhost_chip_support\n", __func__);
+ kfree(nvhost_bus_inst);
+ nvhost_bus_inst = NULL;
+ return -ENOMEM;
+ }
+
+ nvhost_bus_inst->nvhost_bus_type.name = "nvhost";
+ nvhost_bus_inst->nvhost_bus_type.match = nvhost_bus_match;
+ nvhost_bus_inst->nvhost_bus_type.pm = &nvhost_dev_pm_ops;
+ nvhost_bus_inst->nvhost_chip_ops = chip_ops;
+
+ err = bus_register(&nvhost_bus_inst->nvhost_bus_type);
return err;
}
postcore_initcall(nvhost_bus_init);
-
diff --git a/drivers/video/tegra/host/bus.h b/drivers/video/tegra/host/bus.h
new file mode 100644
index 00000000..99f8203
--- /dev/null
+++ b/drivers/video/tegra/host/bus.h
@@ -0,0 +1,38 @@
+/*
+ * drivers/video/tegra/host/bus.h
+ *
+ * Tegra Graphics Host bus API header
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVHOST_BUS_H
+#define __NVHOST_BUS_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include "chip_support.h"
+
+struct nvhost_bus {
+ struct nvhost_chip_support *nvhost_chip_ops;
+ struct bus_type nvhost_bus_type;
+};
+
+struct nvhost_bus *nvhost_bus_get(void);
+
+extern struct nvhost_bus *nvhost_bus_inst;
+
+#endif
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index b49c26e..fd632a6 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -36,7 +36,7 @@
#include <linux/nvhost.h>
#include <linux/nvhost_ioctl.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <mach/iomap.h>
@@ -44,6 +44,11 @@
#include "debug.h"
#include "bus_client.h"
#include "dev.h"
+#include "nvhost_acm.h"
+
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
void nvhost_read_module_regs(struct nvhost_device *ndev,
u32 offset, int count, u32 *values)
@@ -85,45 +90,6 @@ struct nvhost_channel_userctx {
int clientid;
};
-/*
- * Write cmdbuf to ftrace output. Checks if cmdbuf contents should be output
- * and mmaps the cmdbuf contents if required.
- */
-static void trace_write_cmdbufs(struct nvhost_job *job)
-{
- struct nvmap_handle_ref handle;
- void *mem = NULL;
- int i = 0;
-
- for (i = 0; i < job->num_gathers; i++) {
- struct nvhost_channel_gather *gather = &job->gathers[i];
- if (nvhost_debug_trace_cmdbuf) {
- handle.handle = nvmap_id_to_handle(gather->mem_id);
- mem = nvmap_mmap(&handle);
- if (IS_ERR_OR_NULL(mem))
- mem = NULL;
- };
-
- if (mem) {
- u32 i;
- /*
- * Write in batches of 128 as there seems to be a limit
- * of how much you can output to ftrace at once.
- */
- for (i = 0; i < gather->words; i += TRACE_MAX_LENGTH) {
- trace_nvhost_channel_write_cmdbuf_data(
- job->ch->dev->name,
- gather->mem_id,
- min(gather->words - i,
- TRACE_MAX_LENGTH),
- gather->offset + i * sizeof(u32),
- mem);
- }
- nvmap_munmap(&handle, mem);
- }
- }
-}
-
static int nvhost_channelrelease(struct inode *inode, struct file *filp)
{
struct nvhost_channel_userctx *priv = filp->private_data;
@@ -174,6 +140,7 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
priv->priority = NVHOST_PRIORITY_MEDIUM;
priv->clientid = atomic_add_return(1,
&nvhost_get_host(ch->dev)->clientid);
+ priv->timeout = MAX_STUCK_CHECK_COUNT * SYNCPT_CHECK_PERIOD;
priv->job = nvhost_job_alloc(ch, priv->hwctx, &priv->hdr,
NULL, priv->priority, priv->clientid);
@@ -364,8 +331,6 @@ static int nvhost_ioctl_channel_flush(
ctx->timeout = nvhost_debug_force_timeout_val;
}
- trace_write_cmdbufs(ctx->job);
-
/* context switch if needed, and submit user's gathers to the channel */
err = nvhost_channel_submit(ctx->job);
args->value = ctx->job->syncpt_end;
@@ -375,12 +340,11 @@ static int nvhost_ioctl_channel_flush(
return err;
}
-static int nvhost_ioctl_channel_read_3d_reg(
- struct nvhost_channel_userctx *ctx,
+static int nvhost_ioctl_channel_read_3d_reg(struct nvhost_channel_userctx *ctx,
struct nvhost_read_3d_reg_args *args)
{
- BUG_ON(!channel_op(ctx->ch).read3dreg);
- return channel_op(ctx->ch).read3dreg(ctx->ch, ctx->hwctx,
+ BUG_ON(!channel_op().read3dreg);
+ return channel_op().read3dreg(ctx->ch, ctx->hwctx,
args->offset, &args->value);
}
@@ -535,18 +499,23 @@ int nvhost_client_user_init(struct nvhost_device *dev)
int err, devno;
struct nvhost_channel *ch = dev->channel;
+ err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
+ if (err < 0) {
+ dev_err(&dev->dev, "failed to allocate devno\n");
+ goto fail;
+ }
cdev_init(&ch->cdev, &nvhost_channelops);
ch->cdev.owner = THIS_MODULE;
- devno = MKDEV(nvhost_major, nvhost_minor + dev->index);
err = cdev_add(&ch->cdev, devno, 1);
if (err < 0) {
dev_err(&dev->dev,
"failed to add chan %i cdev\n", dev->index);
goto fail;
}
- ch->node = device_create(nvhost_get_host(dev)->nvhost_class, NULL, devno, NULL,
+ ch->node = device_create(nvhost_get_host(dev)->nvhost_class,
+ NULL, devno, NULL,
IFACE_NAME "-%s", dev->name);
if (IS_ERR(ch->node)) {
err = PTR_ERR(ch->node);
@@ -564,7 +533,11 @@ int nvhost_client_device_init(struct nvhost_device *dev)
{
int err;
struct nvhost_master *nvhost_master = nvhost_get_host(dev);
- struct nvhost_channel *ch = &nvhost_master->channels[dev->index];
+ struct nvhost_channel *ch;
+
+ ch = nvhost_alloc_channel(dev->index);
+ if (ch == NULL)
+ return -ENODEV;
/* store the pointer to this device for channel */
ch->dev = dev;
@@ -587,6 +560,7 @@ int nvhost_client_device_init(struct nvhost_device *dev)
fail:
/* Add clean-up */
+ nvhost_free_channel(ch);
return err;
}
diff --git a/drivers/video/tegra/host/chip_support.c b/drivers/video/tegra/host/chip_support.c
new file mode 100644
index 00000000..9abb1fa
--- /dev/null
+++ b/drivers/video/tegra/host/chip_support.c
@@ -0,0 +1,56 @@
+/*
+ * drivers/video/tegra/host/chip_support.c
+ *
+ * Tegra Graphics Host Chip support module
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/errno.h>
+
+#include <mach/hardware.h>
+
+#include "bus.h"
+#include "chip_support.h"
+#include "t20/t20.h"
+#include "t30/t30.h"
+
+struct nvhost_chip_support *nvhost_get_chip_ops(void)
+{
+ return (nvhost_bus_get())->nvhost_chip_ops;
+}
+
+int nvhost_init_chip_support(struct nvhost_master *host)
+{
+ int err = 0;
+ struct nvhost_chip_support *chip_ops;
+
+ chip_ops = nvhost_get_chip_ops();
+
+ switch (tegra_get_chipid()) {
+ case TEGRA_CHIPID_TEGRA2:
+ err = nvhost_init_t20_support(host, chip_ops);
+ break;
+
+ case TEGRA_CHIPID_TEGRA3:
+ err = nvhost_init_t30_support(host, chip_ops);
+ break;
+
+ default:
+ err = -ENODEV;
+ }
+
+ return err;
+}
diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h
index 6727e7a..edc5f6a 100644
--- a/drivers/video/tegra/host/chip_support.h
+++ b/drivers/video/tegra/host/chip_support.h
@@ -21,21 +21,26 @@
#define _NVHOST_CHIP_SUPPORT_H_
#include <linux/types.h>
+#include "bus.h"
+
struct output;
+
+struct nvhost_master;
+struct nvhost_intr;
+struct nvhost_syncpt;
struct nvhost_waitchk;
struct nvhost_userctx_timeout;
-struct nvhost_master;
struct nvhost_channel;
struct nvmap_handle;
struct nvmap_client;
struct nvhost_hwctx;
struct nvhost_cdma;
-struct nvhost_intr;
+struct nvhost_job;
struct push_buffer;
struct nvhost_syncpt;
-struct nvhost_master;
struct dentry;
struct nvhost_job;
+struct nvhost_intr_syncpt;
struct nvhost_chip_support {
struct {
@@ -64,11 +69,6 @@ struct nvhost_chip_support {
u32 syncpt_incrs,
u32 syncval,
u32 nr_slots);
- void (*timeout_pb_incr)(struct nvhost_cdma *,
- u32 getptr,
- u32 syncpt_incrs,
- u32 nr_slots,
- bool exec_ctxsave);
} cdma;
struct {
@@ -133,9 +133,22 @@ struct nvhost_chip_support {
} intr;
struct {
- struct nvhost_device *(*get_nvhost_device)(struct nvhost_master *host,
- char *name);
+ struct nvhost_device *(*get_nvhost_device)(char *name);
+ struct nvhost_channel *(*alloc_nvhost_channel)(int chid);
+ void (*free_nvhost_channel)(struct nvhost_channel *ch);
} nvhost_dev;
};
+struct nvhost_chip_support *nvhost_get_chip_ops(void);
+
+#define host_device_op() nvhost_get_chip_ops()->nvhost_dev
+#define channel_cdma_op() nvhost_get_chip_ops()->cdma
+#define channel_op() nvhost_get_chip_ops()->channel
+#define syncpt_op() nvhost_get_chip_ops()->syncpt
+#define intr_op() nvhost_get_chip_ops()->intr
+#define cdma_op() nvhost_get_chip_ops()->cdma
+#define cdma_pb_op() nvhost_get_chip_ops()->push_buffer
+
+int nvhost_init_chip_support(struct nvhost_master *);
+
#endif /* _NVHOST_CHIP_SUPPORT_H_ */
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index 91436c9..8a26f92 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -22,8 +22,12 @@
#include <linux/io.h>
+#include "bus.h"
#include "dev.h"
#include "debug.h"
+#include "nvhost_acm.h"
+#include "nvhost_channel.h"
+#include "chip_support.h"
pid_t nvhost_debug_null_kickoff_pid;
unsigned int nvhost_debug_trace_cmdbuf;
@@ -59,8 +63,8 @@ static int show_channels(struct device *dev, void *data)
mutex_lock(&ch->reflock);
if (ch->refcount) {
mutex_lock(&ch->cdma.lock);
- m->op.debug.show_channel_fifo(m, ch, o, nvdev->index);
- m->op.debug.show_channel_cdma(m, ch, o, nvdev->index);
+ nvhost_get_chip_ops()->debug.show_channel_fifo(m, ch, o, nvdev->index);
+ nvhost_get_chip_ops()->debug.show_channel_cdma(m, ch, o, nvdev->index);
mutex_unlock(&ch->cdma.lock);
}
mutex_unlock(&ch->reflock);
@@ -72,7 +76,7 @@ static int show_channels(struct device *dev, void *data)
static void show_syncpts(struct nvhost_master *m, struct output *o)
{
int i;
- BUG_ON(!m->op.syncpt.name);
+ BUG_ON(!nvhost_get_chip_ops()->syncpt.name);
nvhost_debug_output(o, "---- syncpts ----\n");
for (i = 0; i < m->syncpt.nb_pts; i++) {
u32 max = nvhost_syncpt_read_max(&m->syncpt, i);
@@ -80,7 +84,7 @@ static void show_syncpts(struct nvhost_master *m, struct output *o)
if (!min && !max)
continue;
nvhost_debug_output(o, "id %d (%s) min %d max %d\n",
- i, m->op.syncpt.name(&m->syncpt, i),
+ i, nvhost_get_chip_ops()->syncpt.name(&m->syncpt, i),
min, max);
}
@@ -99,10 +103,10 @@ static void show_all(struct nvhost_master *m, struct output *o)
{
nvhost_module_busy(m->dev);
- m->op.debug.show_mlocks(m, o);
+ nvhost_get_chip_ops()->debug.show_mlocks(m, o);
show_syncpts(m, o);
nvhost_debug_output(o, "---- channels ----\n");
- bus_for_each_dev(&nvhost_bus_type, NULL, o, show_channels);
+ bus_for_each_dev(&(nvhost_bus_get())->nvhost_bus_type, NULL, o, show_channels);
nvhost_module_idle(m->dev);
}
@@ -142,8 +146,8 @@ void nvhost_debug_init(struct nvhost_master *master)
debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
&nvhost_debug_trace_cmdbuf);
- if (master->op.debug.debug_init)
- master->op.debug.debug_init(de);
+ if (nvhost_get_chip_ops()->debug.debug_init)
+ nvhost_get_chip_ops()->debug.debug_init(de);
debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
&nvhost_debug_force_timeout_pid);
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
index 2e1ffee..ca73528 100644
--- a/drivers/video/tegra/host/dev.c
+++ b/drivers/video/tegra/host/dev.c
@@ -36,22 +36,21 @@
#include <linux/nvhost.h>
#include <linux/nvhost_ioctl.h>
-#include <mach/nvmap.h>
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <mach/iomap.h>
#include "debug.h"
-#include "nvhost_job.h"
#include "t20/t20.h"
#include "t30/t30.h"
#include "bus_client.h"
+#include "nvhost_acm.h"
+#include <linux/nvmap.h>
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
#define DRIVER_NAME "host1x"
-int nvhost_major;
-int nvhost_minor;
-
static unsigned int register_sets;
struct nvhost_ctrl_userctx {
@@ -79,7 +78,8 @@ static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
static int nvhost_ctrlopen(struct inode *inode, struct file *filp)
{
- struct nvhost_master *host = container_of(inode->i_cdev, struct nvhost_master, cdev);
+ struct nvhost_master *host =
+ container_of(inode->i_cdev, struct nvhost_master, cdev);
struct nvhost_ctrl_userctx *priv;
u32 *mod_locks;
@@ -167,24 +167,21 @@ static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
return err;
}
-static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
- u32 id)
+static int match_by_moduleid(struct device *dev, void *data)
{
- int i;
+ struct nvhost_device *ndev = to_nvhost_device(dev);
+ u32 id = (u32)data;
- for (i = 0; i < host->nb_channels; i++) {
- struct nvhost_device *ndev = host->channels[i].dev;
+ return id == ndev->moduleid;
+}
- /* display and dsi do not use channel for register programming.
- * so their channels do not have device instance.
- * hence skip such channels from here. */
- if (ndev == NULL)
- continue;
+static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
+ u32 id)
+{
+ struct device *dev = bus_find_device(&nvhost_bus_inst->nvhost_bus_type, NULL, (void *)id,
+ match_by_moduleid);
- if (id == ndev->moduleid)
- return ndev;
- }
- return NULL;
+ return dev ? to_nvhost_device(dev) : NULL;
}
static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
@@ -329,9 +326,7 @@ static int __devinit nvhost_user_init(struct nvhost_master *host)
goto fail;
}
- err = alloc_chrdev_region(&devno, nvhost_minor,
- host->nb_channels + 1, IFACE_NAME);
- nvhost_major = MAJOR(devno);
+ err = alloc_chrdev_region(&devno, 0, 1, IFACE_NAME);
if (err < 0) {
dev_err(&host->dev->dev, "failed to reserve chrdev region\n");
goto fail;
@@ -339,7 +334,6 @@ static int __devinit nvhost_user_init(struct nvhost_master *host)
cdev_init(&host->cdev, &nvhost_ctrlops);
host->cdev.owner = THIS_MODULE;
- devno = MKDEV(nvhost_major, nvhost_minor + host->nb_channels);
err = cdev_add(&host->cdev, devno, 1);
if (err < 0)
goto fail;
@@ -358,45 +352,40 @@ fail:
struct nvhost_device *nvhost_get_device(char *name)
{
- BUG_ON(!host_device_op(nvhost).get_nvhost_device);
- return host_device_op(nvhost).get_nvhost_device(nvhost, name);
+ BUG_ON(!host_device_op().get_nvhost_device);
+ return host_device_op().get_nvhost_device(name);
}
-static void nvhost_remove_chip_support(struct nvhost_master *host)
+struct nvhost_channel *nvhost_alloc_channel(int index)
{
- kfree(host->channels);
- host->channels = 0;
+ BUG_ON(!host_device_op().alloc_nvhost_channel);
+ return host_device_op().alloc_nvhost_channel(index);
+}
+
+void nvhost_free_channel(struct nvhost_channel *ch)
+{
+ BUG_ON(!host_device_op().free_nvhost_channel);
+ host_device_op().free_nvhost_channel(ch);
+}
+static void nvhost_free_resources(struct nvhost_master *host)
+{
kfree(host->intr.syncpt);
host->intr.syncpt = 0;
}
-static int __devinit nvhost_init_chip_support(struct nvhost_master *host)
+static int __devinit nvhost_alloc_resources(struct nvhost_master *host)
{
int err;
- switch (tegra_get_chipid()) {
- case TEGRA_CHIPID_TEGRA2:
- err = nvhost_init_t20_support(host);
- break;
-
- case TEGRA_CHIPID_TEGRA3:
- err = nvhost_init_t30_support(host);
- break;
- default:
- return -ENODEV;
- }
+ err = nvhost_init_chip_support(host);
if (err)
return err;
- /* allocate items sized in chip specific support init */
- host->channels = kzalloc(sizeof(struct nvhost_channel) *
- host->nb_channels, GFP_KERNEL);
-
host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
host->syncpt.nb_pts, GFP_KERNEL);
- if (!(host->channels && host->intr.syncpt)) {
+ if (!host->intr.syncpt) {
/* frees happen in the support removal phase */
return -ENOMEM;
}
@@ -427,13 +416,12 @@ struct nvhost_device tegra_grhost_device = {
.id = -1,
.resource = nvhost_resources,
.num_resources = ARRAY_SIZE(nvhost_resources),
- .finalize_poweron = power_on_host,
- .prepare_poweroff = power_off_host,
.clocks = {{"host1x", UINT_MAX}, {} },
NVHOST_MODULE_NO_POWERGATE_IDS,
};
-static int __devinit nvhost_probe(struct nvhost_device *dev)
+static int __devinit nvhost_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
struct nvhost_master *host;
struct resource *regs, *intr0, *intr1;
@@ -474,7 +462,7 @@ static int __devinit nvhost_probe(struct nvhost_device *dev)
goto fail;
}
- err = nvhost_init_chip_support(host);
+ err = nvhost_alloc_resources(host);
if (err) {
dev_err(&dev->dev, "failed to init chip support\n");
goto fail;
@@ -516,7 +504,7 @@ static int __devinit nvhost_probe(struct nvhost_device *dev)
return 0;
fail:
- nvhost_remove_chip_support(host);
+ nvhost_free_resources(host);
if (host->nvmap)
nvmap_client_put(host->nvmap);
kfree(host);
@@ -528,7 +516,7 @@ static int __exit nvhost_remove(struct nvhost_device *dev)
struct nvhost_master *host = nvhost_get_drvdata(dev);
nvhost_intr_deinit(&host->intr);
nvhost_syncpt_deinit(&host->syncpt);
- nvhost_remove_chip_support(host);
+ nvhost_free_resources(host);
return 0;
}
@@ -557,7 +545,9 @@ static struct nvhost_driver nvhost_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME
- }
+ },
+ .finalize_poweron = power_on_host,
+ .prepare_poweroff = power_off_host,
};
static int __init nvhost_mod_init(void)
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h
index 74d7e16..41c4fb5 100644
--- a/drivers/video/tegra/host/dev.h
+++ b/drivers/video/tegra/host/dev.h
@@ -21,19 +21,16 @@
#ifndef __NVHOST_DEV_H
#define __NVHOST_DEV_H
-#include "nvhost_acm.h"
+#include <linux/cdev.h>
#include "nvhost_syncpt.h"
#include "nvhost_intr.h"
-#include "nvhost_channel.h"
#include "chip_support.h"
#define TRACE_MAX_LENGTH 128U
#define IFACE_NAME "nvhost"
-extern int nvhost_major;
-extern int nvhost_minor;
-
struct nvhost_hwctx;
+struct nvhost_channel;
struct nvhost_master {
void __iomem *aperture;
@@ -46,11 +43,6 @@ struct nvhost_master {
struct nvmap_client *nvmap;
struct nvhost_intr intr;
struct nvhost_device *dev;
- struct nvhost_channel *channels;
- u32 nb_channels;
-
- struct nvhost_chip_support op;
-
atomic_t clientid;
};
@@ -59,9 +51,9 @@ extern struct nvhost_master *nvhost;
void nvhost_debug_init(struct nvhost_master *master);
void nvhost_debug_dump(struct nvhost_master *master);
-#define host_device_op(host) (host->op.nvhost_dev)
-
struct nvhost_device *nvhost_get_device(char *name);
+struct nvhost_channel *nvhost_alloc_channel(int index);
+void nvhost_free_channel(struct nvhost_channel *ch);
extern pid_t nvhost_debug_null_kickoff_pid;
diff --git a/drivers/video/tegra/host/dsi/dsi.c b/drivers/video/tegra/host/dsi/dsi.c
index 0e49f59..87da8a6 100644
--- a/drivers/video/tegra/host/dsi/dsi.c
+++ b/drivers/video/tegra/host/dsi/dsi.c
@@ -21,7 +21,8 @@
#include "dev.h"
#include "bus_client.h"
-static int dsi_probe(struct nvhost_device *dev)
+static int dsi_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
return nvhost_client_device_init(dev);
}
diff --git a/drivers/video/tegra/host/gr2d/gr2d.c b/drivers/video/tegra/host/gr2d/gr2d.c
index f88eb72..c91a3aa 100644
--- a/drivers/video/tegra/host/gr2d/gr2d.c
+++ b/drivers/video/tegra/host/gr2d/gr2d.c
@@ -21,7 +21,8 @@
#include "dev.h"
#include "bus_client.h"
-static int __devinit gr2d_probe(struct nvhost_device *dev)
+static int __devinit gr2d_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
return nvhost_client_device_init(dev);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d.c b/drivers/video/tegra/host/gr3d/gr3d.c
index f387d54..b621a47 100644
--- a/drivers/video/tegra/host/gr3d/gr3d.c
+++ b/drivers/video/tegra/host/gr3d/gr3d.c
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/slab.h>
#include "t20/t20.h"
@@ -28,7 +28,13 @@
#include "nvhost_hwctx.h"
#include "dev.h"
#include "gr3d.h"
+#include "gr3d_t20.h"
+#include "gr3d_t30.h"
+#include "scale3d.h"
#include "bus_client.h"
+#include "nvhost_channel.h"
+
+#include <mach/hardware.h>
#ifndef TEGRA_POWERGATE_3D1
#define TEGRA_POWERGATE_3D1 -1
@@ -68,7 +74,6 @@ void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *p, u32 *ptr)
}
/*** ctx3d ***/
-
struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
struct nvhost_channel *ch, bool map_restore)
{
@@ -150,8 +155,75 @@ int nvhost_gr3d_prepare_power_off(struct nvhost_device *dev)
return host1x_save_context(dev, NVSYNCPT_3D);
}
-static int __devinit gr3d_probe(struct nvhost_device *dev)
+enum gr3d_ip_ver {
+ gr3d_01,
+ gr3d_02,
+};
+
+struct gr3d_desc {
+ void (*finalize_poweron)(struct nvhost_device *dev);
+ void (*busy)(struct nvhost_device *);
+ void (*idle)(struct nvhost_device *);
+ void (*suspend_ndev)(struct nvhost_device *);
+ void (*init)(struct nvhost_device *dev);
+ void (*deinit)(struct nvhost_device *dev);
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
+};
+
+static const struct gr3d_desc gr3d[] = {
+ [gr3d_01] = {
+ .finalize_poweron = NULL,
+ .busy = NULL,
+ .idle = NULL,
+ .suspend_ndev = NULL,
+ .init = NULL,
+ .deinit = NULL,
+ .prepare_poweroff = nvhost_gr3d_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
+ },
+ [gr3d_02] = {
+ .finalize_poweron = NULL,
+ .busy = nvhost_scale3d_notify_busy,
+ .idle = nvhost_scale3d_notify_idle,
+ .suspend_ndev = nvhost_scale3d_suspend,
+ .init = nvhost_scale3d_init,
+ .deinit = nvhost_scale3d_deinit,
+ .prepare_poweroff = nvhost_gr3d_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
+ },
+};
+
+static struct nvhost_device_id gr3d_id[] = {
+ { "gr3d01", gr3d_01 },
+ { "gr3d02", gr3d_02 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(nvhost, gr3d_id);
+
+static int __devinit gr3d_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
+ int index = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ index = id_table->driver_data;
+
+ drv->finalize_poweron = gr3d[index].finalize_poweron;
+ drv->busy = gr3d[index].busy;
+ drv->idle = gr3d[index].idle;
+ drv->suspend_ndev = gr3d[index].suspend_ndev;
+ drv->init = gr3d[index].init;
+ drv->deinit = gr3d[index].deinit;
+ drv->prepare_poweroff = gr3d[index].prepare_poweroff;
+ drv->alloc_hwctx_handler = gr3d[index].alloc_hwctx_handler;
+
+ /* reset device name so that consistent device name can be
+ * found in clock tree */
+ dev->name = "gr3d";
+
return nvhost_client_device_init(dev);
}
@@ -184,7 +256,8 @@ static struct nvhost_driver gr3d_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "gr3d",
- }
+ },
+ .id_table = gr3d_id,
};
static int __init gr3d_init(void)
@@ -196,8 +269,10 @@ static int __init gr3d_init(void)
return -ENXIO;
err = nvhost_device_register(gr3d_device);
- if (err)
+ if (err) {
+ pr_err("Could not register 3D device\n");
return err;
+ }
return nvhost_driver_register(&gr3d_driver);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.c b/drivers/video/tegra/host/gr3d/gr3d_t20.c
index 9ca990f..c0efac0 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t20.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.c
@@ -19,6 +19,7 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
#include "dev.h"
#include "host1x/host1x_channel.h"
#include "host1x/host1x_hardware.h"
@@ -136,8 +137,9 @@ static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
nvhost_cdma_push_gather(cdma,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ nvhost_get_host(nctx->channel->dev)->nvmap,
+ p->save_buf->handle,
+ 0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c
index 8ca6b7b..93d98dfa 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t30.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c
@@ -19,6 +19,8 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
+#include "nvhost_cdma.h"
#include "dev.h"
#include "host1x/host1x_hardware.h"
#include "host1x/host1x_syncpt.h"
@@ -71,7 +73,6 @@ static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
HWCTX_REGINFO(0xa02, 10, DIRECT),
HWCTX_REGINFO(0xb04, 1, DIRECT),
HWCTX_REGINFO(0xb06, 13, DIRECT),
- HWCTX_REGINFO(0xe42, 2, DIRECT), /* HW bug workaround */
};
static const struct hwctx_reginfo ctxsave_regs_3d_perset[] = {
@@ -143,8 +144,9 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
ctx->restore_phys);
/* gather the save buffer */
nvhost_cdma_push_gather(cdma,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
- (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
+ nvhost_get_host(nctx->channel->dev)->nvmap,
+ p->save_buf->handle,
+ 0,
nvhost_opcode_gather(p->save_size),
p->save_phys);
}
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.c b/drivers/video/tegra/host/host1x/host1x_cdma.c
index cdd60267..fcb1f05 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.c
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.c
@@ -19,7 +19,9 @@
*/
#include <linux/slab.h>
+#include "nvhost_acm.h"
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
#include "dev.h"
#include "host1x_hardware.h"
@@ -66,8 +68,8 @@ static int push_buffer_init(struct push_buffer *pb)
pb->phys = 0;
pb->nvmap = NULL;
- BUG_ON(!cdma_pb_op(cdma).reset);
- cdma_pb_op(cdma).reset(pb);
+ BUG_ON(!cdma_pb_op().reset);
+ cdma_pb_op().reset(pb);
/* allocate and map pushbuffer memory */
pb->mem = nvmap_alloc(nvmap, PUSH_BUFFER_SIZE + 4, 32,
@@ -101,7 +103,7 @@ static int push_buffer_init(struct push_buffer *pb)
return 0;
fail:
- cdma_pb_op(cdma).destroy(pb);
+ cdma_pb_op().destroy(pb);
return -ENOMEM;
}
@@ -191,96 +193,25 @@ static u32 push_buffer_putptr(struct push_buffer *pb)
*/
/**
- * Init timeout and syncpt incr buffer resources
+ * Init timeout resources
*/
static int cdma_timeout_init(struct nvhost_cdma *cdma,
u32 syncpt_id)
{
- struct nvhost_master *dev = cdma_to_dev(cdma);
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
- struct nvhost_channel *ch = cdma_to_channel(cdma);
- u32 i = 0;
-
if (syncpt_id == NVSYNCPT_INVALID)
return -EINVAL;
- /* allocate and map syncpt incr memory */
- sb->mem = nvmap_alloc(nvmap,
- (SYNCPT_INCR_BUFFER_SIZE_WORDS * sizeof(u32)), 32,
- NVMAP_HANDLE_WRITE_COMBINE, 0);
- if (IS_ERR_OR_NULL(sb->mem)) {
- sb->mem = NULL;
- goto fail;
- }
- sb->mapped = nvmap_mmap(sb->mem);
- if (sb->mapped == NULL)
- goto fail;
-
- /* pin syncpt buffer and get physical address */
- sb->phys = nvmap_pin(nvmap, sb->mem);
- if (sb->phys >= 0xfffff000) {
- sb->phys = 0;
- goto fail;
- }
-
- dev_dbg(&dev->dev->dev, "%s: SYNCPT_INCR buffer at 0x%x\n",
- __func__, sb->phys);
-
- sb->words_per_incr = (syncpt_id == NVSYNCPT_3D) ? 5 : 3;
- sb->incr_per_buffer = (SYNCPT_INCR_BUFFER_SIZE_WORDS /
- sb->words_per_incr);
-
- /* init buffer with SETCL and INCR_SYNCPT methods */
- while (i < sb->incr_per_buffer) {
- sb->mapped[i++] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
- 0, 0);
- sb->mapped[i++] = nvhost_opcode_imm_incr_syncpt(
- NV_SYNCPT_IMMEDIATE,
- syncpt_id);
- if (syncpt_id == NVSYNCPT_3D) {
- /* also contains base increments */
- sb->mapped[i++] = nvhost_opcode_nonincr(
- NV_CLASS_HOST_INCR_SYNCPT_BASE,
- 1);
- sb->mapped[i++] = nvhost_class_host_incr_syncpt_base(
- NVWAITBASE_3D, 1);
- }
- sb->mapped[i++] = nvhost_opcode_setclass(ch->dev->class,
- 0, 0);
- }
- wmb();
-
INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler);
cdma->timeout.initialized = true;
return 0;
-fail:
- cdma_op(cdma).timeout_destroy(cdma);
- return -ENOMEM;
}
/**
- * Clean up timeout syncpt buffer resources
+ * Clean up timeout resources
*/
static void cdma_timeout_destroy(struct nvhost_cdma *cdma)
{
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
-
- if (sb->mapped)
- nvmap_munmap(sb->mem, sb->mapped);
-
- if (sb->phys != 0)
- nvmap_unpin(nvmap, sb->mem);
-
- if (sb->mem)
- nvmap_free(nvmap, sb->mem);
-
- sb->mem = NULL;
- sb->mapped = NULL;
- sb->phys = 0;
-
if (cdma->timeout.initialized)
cancel_delayed_work(&cdma->timeout.wq);
cdma->timeout.initialized = false;
@@ -324,73 +255,6 @@ static void cdma_timeout_cpu_incr(struct nvhost_cdma *cdma, u32 getptr,
}
/**
- * This routine is called at the point we transition back into a timed
- * ctx. The syncpts are incremented via pushbuffer with a flag indicating
- * whether there's a CTXSAVE that should be still executed (for the
- * preceding HW ctx).
- */
-static void cdma_timeout_pb_incr(struct nvhost_cdma *cdma, u32 getptr,
- u32 syncpt_incrs, u32 nr_slots,
- bool exec_ctxsave)
-{
- struct nvhost_master *dev = cdma_to_dev(cdma);
- struct syncpt_buffer *sb = &cdma->syncpt_buffer;
- struct push_buffer *pb = &cdma->push_buffer;
- struct host1x_hwctx *hwctx = to_host1x_hwctx(cdma->timeout.ctx);
- u32 getidx, *p;
-
- /* should have enough slots to incr to desired count */
- BUG_ON(syncpt_incrs > (nr_slots * sb->incr_per_buffer));
-
- getidx = getptr - pb->phys;
- if (exec_ctxsave) {
- /* don't disrupt the CTXSAVE of a good/non-timed out ctx */
- nr_slots -= hwctx->save_slots;
- syncpt_incrs -= hwctx->save_incrs;
-
- getidx += (hwctx->save_slots * 8);
- getidx &= (PUSH_BUFFER_SIZE - 1);
-
- dev_dbg(&dev->dev->dev,
- "%s: exec CTXSAVE of prev ctx (slots %d, incrs %d)\n",
- __func__, nr_slots, syncpt_incrs);
- }
-
- while (syncpt_incrs) {
- u32 incrs, count;
-
- /* GATHER count are incrs * number of DWORDs per incr */
- incrs = min(syncpt_incrs, sb->incr_per_buffer);
- count = incrs * sb->words_per_incr;
-
- p = (u32 *)((u32)pb->mapped + getidx);
- *(p++) = nvhost_opcode_gather(count);
- *(p++) = sb->phys;
-
- dev_dbg(&dev->dev->dev,
- "%s: GATHER at 0x%x, from 0x%x, dcount = %d\n",
- __func__,
- pb->phys + getidx, sb->phys,
- (incrs * sb->words_per_incr));
-
- syncpt_incrs -= incrs;
- getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
- nr_slots--;
- }
-
- /* NOP remaining slots */
- while (nr_slots--) {
- p = (u32 *)((u32)pb->mapped + getidx);
- *(p++) = NVHOST_OPCODE_NOOP;
- *(p++) = NVHOST_OPCODE_NOOP;
- dev_dbg(&dev->dev->dev, "%s: NOP at 0x%x\n",
- __func__, pb->phys + getidx);
- getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
- }
- wmb();
-}
-
-/**
* Start channel DMA
*/
static void cdma_start(struct nvhost_cdma *cdma)
@@ -400,8 +264,8 @@ static void cdma_start(struct nvhost_cdma *cdma)
if (cdma->running)
return;
- BUG_ON(!cdma_pb_op(cdma).putptr);
- cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ BUG_ON(!cdma_pb_op().putptr);
+ cdma->last_put = cdma_pb_op().putptr(&cdma->push_buffer);
writel(host1x_channel_dmactrl(true, false, false),
chan_regs + HOST1X_CHANNEL_DMACTRL);
@@ -435,8 +299,8 @@ static void cdma_timeout_restart(struct nvhost_cdma *cdma, u32 getptr)
if (cdma->running)
return;
- BUG_ON(!cdma_pb_op(cdma).putptr);
- cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ BUG_ON(!cdma_pb_op().putptr);
+ cdma->last_put = cdma_pb_op().putptr(&cdma->push_buffer);
writel(host1x_channel_dmactrl(true, false, false),
chan_regs + HOST1X_CHANNEL_DMACTRL);
@@ -475,9 +339,9 @@ static void cdma_timeout_restart(struct nvhost_cdma *cdma, u32 getptr)
static void cdma_kick(struct nvhost_cdma *cdma)
{
u32 put;
- BUG_ON(!cdma_pb_op(cdma).putptr);
+ BUG_ON(!cdma_pb_op().putptr);
- put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ put = cdma_pb_op().putptr(&cdma->push_buffer);
if (put != cdma->last_put) {
void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
@@ -629,37 +493,36 @@ static void cdma_timeout_handler(struct work_struct *work)
"%s: timeout: %d (%s) ctx 0x%p, HW thresh %d, done %d\n",
__func__,
cdma->timeout.syncpt_id,
- syncpt_op(sp).name(sp, cdma->timeout.syncpt_id),
+ syncpt_op().name(sp, cdma->timeout.syncpt_id),
cdma->timeout.ctx,
syncpt_val, cdma->timeout.syncpt_val);
/* stop HW, resetting channel/module */
- cdma_op(cdma).timeout_teardown_begin(cdma);
+ cdma_op().timeout_teardown_begin(cdma);
nvhost_cdma_update_sync_queue(cdma, sp, &dev->dev->dev);
mutex_unlock(&cdma->lock);
}
-int host1x_init_cdma_support(struct nvhost_master *host)
+int host1x_init_cdma_support(struct nvhost_chip_support *op)
{
- host->op.cdma.start = cdma_start;
- host->op.cdma.stop = cdma_stop;
- host->op.cdma.kick = cdma_kick;
-
- host->op.cdma.timeout_init = cdma_timeout_init;
- host->op.cdma.timeout_destroy = cdma_timeout_destroy;
- host->op.cdma.timeout_teardown_begin = cdma_timeout_teardown_begin;
- host->op.cdma.timeout_teardown_end = cdma_timeout_teardown_end;
- host->op.cdma.timeout_cpu_incr = cdma_timeout_cpu_incr;
- host->op.cdma.timeout_pb_incr = cdma_timeout_pb_incr;
-
- host->op.push_buffer.reset = push_buffer_reset;
- host->op.push_buffer.init = push_buffer_init;
- host->op.push_buffer.destroy = push_buffer_destroy;
- host->op.push_buffer.push_to = push_buffer_push_to;
- host->op.push_buffer.pop_from = push_buffer_pop_from;
- host->op.push_buffer.space = push_buffer_space;
- host->op.push_buffer.putptr = push_buffer_putptr;
+ op->cdma.start = cdma_start;
+ op->cdma.stop = cdma_stop;
+ op->cdma.kick = cdma_kick;
+
+ op->cdma.timeout_init = cdma_timeout_init;
+ op->cdma.timeout_destroy = cdma_timeout_destroy;
+ op->cdma.timeout_teardown_begin = cdma_timeout_teardown_begin;
+ op->cdma.timeout_teardown_end = cdma_timeout_teardown_end;
+ op->cdma.timeout_cpu_incr = cdma_timeout_cpu_incr;
+
+ op->push_buffer.reset = push_buffer_reset;
+ op->push_buffer.init = push_buffer_init;
+ op->push_buffer.destroy = push_buffer_destroy;
+ op->push_buffer.push_to = push_buffer_push_to;
+ op->push_buffer.pop_from = push_buffer_pop_from;
+ op->push_buffer.space = push_buffer_space;
+ op->push_buffer.putptr = push_buffer_putptr;
return 0;
}
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.h b/drivers/video/tegra/host/host1x/host1x_cdma.h
index 6090923..3740972 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.h
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.h
@@ -36,6 +36,6 @@
* and replaces the original timed out contexts GATHER slots */
#define SYNCPT_INCR_BUFFER_SIZE_WORDS (4096 / sizeof(u32))
-int host1x_init_cdma_support(struct nvhost_master *);
+int host1x_init_cdma_support(struct nvhost_chip_support *);
#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c
index b16a34f..8c4a7a5 100644
--- a/drivers/video/tegra/host/host1x/host1x_channel.c
+++ b/drivers/video/tegra/host/host1x/host1x_channel.c
@@ -20,6 +20,8 @@
#include "nvhost_channel.h"
#include "dev.h"
+#include "nvhost_acm.h"
+#include "nvhost_job.h"
#include "nvhost_hwctx.h"
#include <trace/events/nvhost.h>
#include <linux/slab.h>
@@ -142,6 +144,7 @@ static void submit_ctxrestore(struct nvhost_job *job)
nvhost_cdma_push_gather(&ch->cdma,
host->nvmap,
nvmap_ref_to_handle(ctx->restore),
+ 0,
nvhost_opcode_gather(ctx->restore_size),
ctx->restore_phys);
@@ -179,12 +182,14 @@ void submit_nullkickoff(struct nvhost_job *job, int user_syncpt_incrs)
void submit_gathers(struct nvhost_job *job)
{
/* push user gathers */
- int i = 0;
- for ( ; i < job->num_gathers; i++) {
+ int i;
+ for (i = 0 ; i < job->num_gathers; i++) {
u32 op1 = nvhost_opcode_gather(job->gathers[i].words);
u32 op2 = job->gathers[i].mem;
nvhost_cdma_push_gather(&job->ch->cdma,
- job->nvmap, job->unpins[i/2],
+ job->nvmap,
+ nvmap_id_to_handle(job->gathers[i].mem_id),
+ job->gathers[i].offset,
op1, op2);
}
}
@@ -198,6 +203,7 @@ int host1x_channel_submit(struct nvhost_job *job)
u32 syncval;
int err;
void *completed_waiter = NULL, *ctxsave_waiter = NULL;
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
/* Bail out on timed out contexts */
if (job->hwctx && job->hwctx->has_timedout)
@@ -205,8 +211,8 @@ int host1x_channel_submit(struct nvhost_job *job)
/* Turn on the client module and host1x */
nvhost_module_busy(ch->dev);
- if (ch->dev->busy)
- ch->dev->busy(ch->dev);
+ if (drv->busy)
+ drv->busy(ch->dev);
/* before error checks, return current max */
prev_max = job->syncpt_end =
@@ -544,6 +550,7 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
void *ref;
void *ctx_waiter = NULL, *wakeup_waiter = NULL;
struct nvhost_job *job;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
ctx_waiter = nvhost_intr_alloc_waiter();
wakeup_waiter = nvhost_intr_alloc_waiter();
@@ -552,8 +559,8 @@ int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
goto done;
}
- if (dev->busy)
- dev->busy(dev);
+ if (drv->busy)
+ drv->busy(dev);
mutex_lock(&ch->submitlock);
hwctx_to_save = ch->cur_ctx;
diff --git a/drivers/video/tegra/host/host1x/host1x_debug.c b/drivers/video/tegra/host/host1x/host1x_debug.c
index 1a1d764..76483d8 100644
--- a/drivers/video/tegra/host/host1x/host1x_debug.c
+++ b/drivers/video/tegra/host/host1x/host1x_debug.c
@@ -25,10 +25,10 @@
#include "dev.h"
#include "debug.h"
+#include "host1x_hardware.h"
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
#include "../../nvmap/nvmap.h"
-
-#include "host1x_hardware.h"
#include "host1x_cdma.h"
#define NVHOST_DEBUG_MAX_PAGE_OFFSET 102400
@@ -174,11 +174,6 @@ static void show_channel_gather(struct output *o, u32 addr,
phys_addr_t pin_addr;
int state, count, i;
- if ((u32)nvmap->handle == NVHOST_CDMA_PUSH_GATHER_CTXSAVE) {
- nvhost_debug_output(o, "[context save]\n");
- return;
- }
-
if (!nvmap->handle || !nvmap->client
|| atomic_read(&nvmap->handle->ref) < 1) {
nvhost_debug_output(o, "[already deallocated]\n");
@@ -394,11 +389,11 @@ static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
nvhost_debug_output(o, "\n");
}
-int nvhost_init_t20_debug_support(struct nvhost_master *host)
+int nvhost_init_t20_debug_support(struct nvhost_chip_support *op)
{
- host->op.debug.show_channel_cdma = t20_debug_show_channel_cdma;
- host->op.debug.show_channel_fifo = t20_debug_show_channel_fifo;
- host->op.debug.show_mlocks = t20_debug_show_mlocks;
+ op->debug.show_channel_cdma = t20_debug_show_channel_cdma;
+ op->debug.show_channel_fifo = t20_debug_show_channel_fifo;
+ op->debug.show_mlocks = t20_debug_show_mlocks;
return 0;
}
diff --git a/drivers/video/tegra/host/host1x/host1x_hwctx.h b/drivers/video/tegra/host/host1x/host1x_hwctx.h
index 7587642d..b5046c4 100644
--- a/drivers/video/tegra/host/host1x/host1x_hwctx.h
+++ b/drivers/video/tegra/host/host1x/host1x_hwctx.h
@@ -24,6 +24,7 @@
#define __NVHOST_HOST1X_HWCTX_H
#include <linux/kref.h>
+#include "nvhost_hwctx.h"
struct nvhost_hwctx_handler;
struct nvhost_channel;
diff --git a/drivers/video/tegra/host/host1x/host1x_intr.c b/drivers/video/tegra/host/host1x/host1x_intr.c
index 47e984e..2b611fa 100644
--- a/drivers/video/tegra/host/host1x/host1x_intr.c
+++ b/drivers/video/tegra/host/host1x/host1x_intr.c
@@ -3,6 +3,7 @@
*
* Tegra Graphics Host Interrupt Management
*
+ * Copyright (C) 2010 Google, Inc.
* Copyright (c) 2010-2012, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,18 +21,69 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/mach/irq.h>
#include "nvhost_intr.h"
#include "dev.h"
#include "host1x_hardware.h"
-
/*** HW host sync management ***/
+static void syncpt_thresh_mask(struct irq_data *data)
+{
+ (void)data;
+}
+
+static void syncpt_thresh_unmask(struct irq_data *data)
+{
+ (void)data;
+}
+
+static void syncpt_thresh_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *sync_regs = irq_desc_get_handler_data(desc);
+ unsigned long reg;
+ int id;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
+ reg = readl(sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
+
+ for_each_set_bit(id, &reg, 32)
+ generic_handle_irq(id + INT_SYNCPT_THRESH_BASE);
+
+ chained_irq_exit(chip, desc);
+}
+
+static struct irq_chip syncpt_thresh_irq = {
+ .name = "syncpt",
+ .irq_mask = syncpt_thresh_mask,
+ .irq_unmask = syncpt_thresh_unmask
+};
+
static void t20_intr_init_host_sync(struct nvhost_intr *intr)
{
struct nvhost_master *dev = intr_to_dev(intr);
void __iomem *sync_regs = dev->sync_aperture;
+ int i, irq;
+
+ writel(0xffffffffUL,
+ sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
+ writel(0xffffffffUL,
+ sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
+
+ for (i = 0; i < INT_SYNCPT_THRESH_NR; i++) {
+ irq = INT_SYNCPT_THRESH_BASE + i;
+ irq_set_chip_and_handler(irq, &syncpt_thresh_irq,
+ handle_simple_irq);
+ irq_set_chip_data(irq, sync_regs);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ irq_set_chained_handler(INT_HOST1X_MPCORE_SYNCPT,
+ syncpt_thresh_cascade);
+ irq_set_handler_data(INT_HOST1X_MPCORE_SYNCPT, sync_regs);
/* disable the ip_busy_timeout. this prevents write drops, etc.
* there's no real way to recover from a hung client anyway.
*/
@@ -198,21 +250,16 @@ static int t20_request_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
return 0;
}
-int nvhost_init_t20_intr_support(struct nvhost_master *host)
+int nvhost_init_t20_intr_support(struct nvhost_chip_support *op)
{
- host->op.intr.init_host_sync = t20_intr_init_host_sync;
- host->op.intr.set_host_clocks_per_usec =
- t20_intr_set_host_clocks_per_usec;
- host->op.intr.set_syncpt_threshold = t20_intr_set_syncpt_threshold;
- host->op.intr.enable_syncpt_intr = t20_intr_enable_syncpt_intr;
- host->op.intr.disable_all_syncpt_intrs =
- t20_intr_disable_all_syncpt_intrs;
- host->op.intr.request_host_general_irq =
- t20_intr_request_host_general_irq;
- host->op.intr.free_host_general_irq =
- t20_intr_free_host_general_irq;
- host->op.intr.request_syncpt_irq =
- t20_request_syncpt_irq;
+ op->intr.init_host_sync = t20_intr_init_host_sync;
+ op->intr.set_host_clocks_per_usec = t20_intr_set_host_clocks_per_usec;
+ op->intr.set_syncpt_threshold = t20_intr_set_syncpt_threshold;
+ op->intr.enable_syncpt_intr = t20_intr_enable_syncpt_intr;
+ op->intr.disable_all_syncpt_intrs = t20_intr_disable_all_syncpt_intrs;
+ op->intr.request_host_general_irq = t20_intr_request_host_general_irq;
+ op->intr.free_host_general_irq = t20_intr_free_host_general_irq;
+ op->intr.request_syncpt_irq = t20_request_syncpt_irq;
return 0;
}
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.c b/drivers/video/tegra/host/host1x/host1x_syncpt.c
index b431fa3..b7d6587 100644
--- a/drivers/video/tegra/host/host1x/host1x_syncpt.c
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.c
@@ -19,10 +19,14 @@
*/
#include <linux/nvhost_ioctl.h>
+#include <linux/io.h>
+#include <trace/events/nvhost.h>
#include "nvhost_syncpt.h"
+#include "nvhost_acm.h"
#include "dev.h"
#include "host1x_syncpt.h"
#include "host1x_hardware.h"
+#include "chip_support.h"
/**
* Write the current syncpoint value back to hw.
@@ -122,6 +126,8 @@ static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
u32 override;
BUG_ON(wait->syncpt_id >= NV_HOST1X_SYNCPT_NB_PTS);
+ trace_nvhost_syncpt_wait_check(wait->mem, wait->offset,
+ wait->syncpt_id, wait->thresh);
if (nvhost_syncpt_is_expired(sp,
wait->syncpt_id, wait->thresh)) {
/*
@@ -135,7 +141,7 @@ static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
dev_dbg(&syncpt_to_dev(sp)->dev->dev,
"drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
wait->syncpt_id,
- syncpt_op(sp).name(sp, wait->syncpt_id),
+ syncpt_op().name(sp, wait->syncpt_id),
wait->thresh,
nvhost_syncpt_read_min(sp, wait->syncpt_id));
@@ -189,7 +195,7 @@ static void t20_syncpt_debug(struct nvhost_syncpt *sp)
continue;
dev_info(&syncpt_to_dev(sp)->dev->dev,
"id %d (%s) min %d max %d\n",
- i, syncpt_op(sp).name(sp, i),
+ i, syncpt_op().name(sp, i),
min, max);
}
@@ -223,23 +229,23 @@ static void syncpt_mutex_unlock(struct nvhost_syncpt *sp,
writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
}
-int host1x_init_syncpt_support(struct nvhost_master *host)
+int host1x_init_syncpt_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
-
host->sync_aperture = host->aperture +
(NV_HOST1X_CHANNEL0_BASE +
HOST1X_CHANNEL_SYNC_REG_BASE);
- host->op.syncpt.reset = t20_syncpt_reset;
- host->op.syncpt.reset_wait_base = t20_syncpt_reset_wait_base;
- host->op.syncpt.read_wait_base = t20_syncpt_read_wait_base;
- host->op.syncpt.update_min = t20_syncpt_update_min;
- host->op.syncpt.cpu_incr = t20_syncpt_cpu_incr;
- host->op.syncpt.wait_check = t20_syncpt_wait_check;
- host->op.syncpt.debug = t20_syncpt_debug;
- host->op.syncpt.name = t20_syncpt_name;
- host->op.syncpt.mutex_try_lock = syncpt_mutex_try_lock;
- host->op.syncpt.mutex_unlock = syncpt_mutex_unlock;
+ op->syncpt.reset = t20_syncpt_reset;
+ op->syncpt.reset_wait_base = t20_syncpt_reset_wait_base;
+ op->syncpt.read_wait_base = t20_syncpt_read_wait_base;
+ op->syncpt.update_min = t20_syncpt_update_min;
+ op->syncpt.cpu_incr = t20_syncpt_cpu_incr;
+ op->syncpt.wait_check = t20_syncpt_wait_check;
+ op->syncpt.debug = t20_syncpt_debug;
+ op->syncpt.name = t20_syncpt_name;
+ op->syncpt.mutex_try_lock = syncpt_mutex_try_lock;
+ op->syncpt.mutex_unlock = syncpt_mutex_unlock;
host->syncpt.nb_pts = NV_HOST1X_SYNCPT_NB_PTS;
host->syncpt.nb_bases = NV_HOST1X_SYNCPT_NB_BASES;
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.h b/drivers/video/tegra/host/host1x/host1x_syncpt.h
index 0d263dc..1e94a2b 100644
--- a/drivers/video/tegra/host/host1x/host1x_syncpt.h
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.h
@@ -71,7 +71,10 @@
#define NVWAITBASE_MPE (4)
struct nvhost_master;
+struct nvhost_chip_support;
+
int host1x_init_syncpt(struct nvhost_master *host);
-int host1x_init_syncpt_support(struct nvhost_master *host);
+int host1x_init_syncpt_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op);
#endif
diff --git a/drivers/video/tegra/host/isp/isp.c b/drivers/video/tegra/host/isp/isp.c
index 9044d40..ae9d7eb 100644
--- a/drivers/video/tegra/host/isp/isp.c
+++ b/drivers/video/tegra/host/isp/isp.c
@@ -25,7 +25,8 @@
#include "dev.h"
#include "bus_client.h"
-static int __devinit isp_probe(struct nvhost_device *dev)
+static int __devinit isp_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
diff --git a/drivers/video/tegra/host/mpe/mpe.c b/drivers/video/tegra/host/mpe/mpe.c
index 36d1d6f2..d8c9da7 100644
--- a/drivers/video/tegra/host/mpe/mpe.c
+++ b/drivers/video/tegra/host/mpe/mpe.c
@@ -19,6 +19,7 @@
*/
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
#include "dev.h"
#include "host1x/host1x_hardware.h"
#include "host1x/host1x_channel.h"
@@ -30,6 +31,7 @@
#include <linux/resource.h>
#include <mach/iomap.h>
+#include <mach/hardware.h>
#include "bus_client.h"
@@ -459,6 +461,7 @@ static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_hwctx_handler *h,
ctx->hwctx.valid = false;
ctx->save_incrs = 3;
ctx->save_thresh = 2;
+ ctx->save_slots = p->save_slots;
ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
ctx->restore_size = restore_size;
ctx->restore_incrs = 1;
@@ -497,7 +500,10 @@ static void ctxmpe_save_push(struct nvhost_hwctx *nctx,
{
struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
- nvhost_cdma_push(cdma,
+ nvhost_cdma_push_gather(cdma,
+ nvhost_get_host(nctx->channel->dev)->nvmap,
+ h->save_buf->handle,
+ 0,
nvhost_opcode_gather(h->save_size),
h->save_phys);
}
@@ -528,9 +534,8 @@ static void ctxmpe_save_service(struct nvhost_hwctx *nctx)
h->syncpt);
}
-struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
- u32 syncpt, u32 waitbase,
- struct nvhost_channel *ch)
+struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch)
{
struct nvmap_client *nvmap;
u32 *save_ptr;
@@ -562,6 +567,7 @@ struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
}
p->save_phys = nvmap_pin(nvmap, p->save_buf);
+ p->save_slots = 1;
setup_save(p, save_ptr);
@@ -579,9 +585,51 @@ int nvhost_mpe_prepare_power_off(struct nvhost_device *dev)
return host1x_save_context(dev, NVSYNCPT_MPE);
}
-static int __devinit mpe_probe(struct nvhost_device *dev)
+enum mpe_ip_ver {
+ mpe_01,
+ mpe_02,
+};
+
+struct mpe_desc {
+ int (*prepare_poweroff)(struct nvhost_device *dev);
+ struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
+ u32 waitbase, struct nvhost_channel *ch);
+};
+
+static const struct mpe_desc mpe[] = {
+ [mpe_01] = {
+ .prepare_poweroff = nvhost_mpe_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
+ },
+ [mpe_02] = {
+ .prepare_poweroff = nvhost_mpe_prepare_power_off,
+ .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
+ },
+};
+
+static struct nvhost_device_id mpe_id[] = {
+ { "mpe01", mpe_01 },
+ { "mpe02", mpe_02 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(nvhost, mpe_id);
+
+static int __devinit mpe_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
+ int index = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ index = id_table->driver_data;
+
+ drv->prepare_poweroff = mpe[index].prepare_poweroff;
+ drv->alloc_hwctx_handler = mpe[index].alloc_hwctx_handler;
+
+ /* reset device name so that consistent device name can be
+ * found in clock tree */
+ dev->name = "mpe";
err = nvhost_client_device_get_resources(dev);
if (err)
@@ -626,7 +674,8 @@ static struct nvhost_driver mpe_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "mpe",
- }
+ },
+ .id_table = mpe_id,
};
static int __init mpe_init(void)
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index f2a61a9..6d96bd0 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -55,15 +55,8 @@ static void do_unpowergate_locked(int id)
tegra_unpowergate_partition(id);
}
-void nvhost_module_reset(struct nvhost_device *dev)
+static void do_module_reset_locked(struct nvhost_device *dev)
{
- dev_dbg(&dev->dev,
- "%s: asserting %s module reset (id %d, id2 %d)\n",
- __func__, dev->name,
- dev->powergate_ids[0], dev->powergate_ids[1]);
-
- mutex_lock(&dev->lock);
-
/* assert module and mc client reset */
if (dev->powergate_ids[0] != -1) {
tegra_powergate_mc_disable(dev->powergate_ids[0]);
@@ -89,7 +82,17 @@ void nvhost_module_reset(struct nvhost_device *dev)
tegra_periph_reset_deassert(dev->clk[1]);
tegra_powergate_mc_enable(dev->powergate_ids[1]);
}
+}
+void nvhost_module_reset(struct nvhost_device *dev)
+{
+ dev_dbg(&dev->dev,
+ "%s: asserting %s module reset (id %d, id2 %d)\n",
+ __func__, dev->name,
+ dev->powergate_ids[0], dev->powergate_ids[1]);
+
+ mutex_lock(&dev->lock);
+ do_module_reset_locked(dev);
mutex_unlock(&dev->lock);
dev_dbg(&dev->dev, "%s: module %s out of reset\n",
@@ -108,15 +111,21 @@ static void to_state_clockgated_locked(struct nvhost_device *dev)
&& dev->can_powergate) {
do_unpowergate_locked(dev->powergate_ids[0]);
do_unpowergate_locked(dev->powergate_ids[1]);
+
+ if (dev->powerup_reset)
+ do_module_reset_locked(dev);
}
dev->powerstate = NVHOST_POWER_STATE_CLOCKGATED;
}
static void to_state_running_locked(struct nvhost_device *dev)
{
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
int prev_state = dev->powerstate;
+
if (dev->powerstate == NVHOST_POWER_STATE_POWERGATED)
to_state_clockgated_locked(dev);
+
if (dev->powerstate == NVHOST_POWER_STATE_CLOCKGATED) {
int i;
@@ -129,8 +138,8 @@ static void to_state_running_locked(struct nvhost_device *dev)
}
if (prev_state == NVHOST_POWER_STATE_POWERGATED
- && dev->finalize_poweron)
- dev->finalize_poweron(dev);
+ && drv->finalize_poweron)
+ drv->finalize_poweron(dev);
}
dev->powerstate = NVHOST_POWER_STATE_RUNNING;
}
@@ -142,12 +151,13 @@ static void to_state_running_locked(struct nvhost_device *dev)
static int to_state_powergated_locked(struct nvhost_device *dev)
{
int err = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
- if (dev->prepare_poweroff
+ if (drv->prepare_poweroff
&& dev->powerstate != NVHOST_POWER_STATE_POWERGATED) {
/* Clock needs to be on in prepare_poweroff */
to_state_running_locked(dev);
- err = dev->prepare_poweroff(dev);
+ err = drv->prepare_poweroff(dev);
if (err)
return err;
}
@@ -179,8 +189,10 @@ static void schedule_clockgating_locked(struct nvhost_device *dev)
void nvhost_module_busy(struct nvhost_device *dev)
{
- if (dev->busy)
- dev->busy(dev);
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
+ if (drv->busy)
+ drv->busy(dev);
mutex_lock(&dev->lock);
cancel_delayed_work(&dev->powerstate_down);
@@ -220,6 +232,7 @@ static void powerstate_down_handler(struct work_struct *work)
void nvhost_module_idle_mult(struct nvhost_device *dev, int refs)
{
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
bool kick = false;
mutex_lock(&dev->lock);
@@ -234,8 +247,8 @@ void nvhost_module_idle_mult(struct nvhost_device *dev, int refs)
if (kick) {
wake_up(&dev->idle_wq);
- if (dev->idle)
- dev->idle(dev);
+ if (drv->idle)
+ drv->idle(dev);
}
}
@@ -397,6 +410,7 @@ static int is_module_idle(struct nvhost_device *dev)
int nvhost_module_suspend(struct nvhost_device *dev)
{
int ret;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
ret = wait_event_timeout(dev->idle_wq, is_module_idle(dev),
ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT);
@@ -411,8 +425,8 @@ int nvhost_module_suspend(struct nvhost_device *dev)
to_state_powergated_locked(dev);
mutex_unlock(&dev->lock);
- if (dev->suspend)
- dev->suspend(dev);
+ if (drv->suspend_ndev)
+ drv->suspend_ndev(dev);
return 0;
}
@@ -420,9 +434,10 @@ int nvhost_module_suspend(struct nvhost_device *dev)
void nvhost_module_deinit(struct nvhost_device *dev)
{
int i;
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
- if (dev->deinit)
- dev->deinit(dev);
+ if (drv->deinit)
+ drv->deinit(dev);
nvhost_module_suspend(dev);
for (i = 0; i < dev->num_clks; i++)
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
index 775d761..a72e18f 100644
--- a/drivers/video/tegra/host/nvhost_cdma.c
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -19,7 +19,11 @@
*/
#include "nvhost_cdma.h"
+#include "nvhost_channel.h"
+#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
#include "dev.h"
+#include "debug.h"
#include <asm/cacheflush.h>
#include <linux/slab.h>
@@ -65,8 +69,8 @@ static unsigned int cdma_status_locked(struct nvhost_cdma *cdma,
return list_empty(&cdma->sync_queue) ? 1 : 0;
case CDMA_EVENT_PUSH_BUFFER_SPACE: {
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).space);
- return cdma_pb_op(cdma).space(pb);
+ BUG_ON(!cdma_pb_op().space);
+ return cdma_pb_op().space(pb);
}
default:
return 0;
@@ -92,7 +96,13 @@ unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma,
trace_nvhost_wait_cdma(cdma_to_channel(cdma)->dev->name,
event);
- BUG_ON(cdma->event != CDMA_EVENT_NONE);
+ /* If somebody has managed to already start waiting, yield */
+ if (cdma->event != CDMA_EVENT_NONE) {
+ mutex_unlock(&cdma->lock);
+ schedule();
+ mutex_lock(&cdma->lock);
+ continue;
+ }
cdma->event = event;
mutex_unlock(&cdma->lock);
@@ -153,7 +163,9 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
struct nvhost_syncpt *sp = &dev->syncpt;
struct nvhost_job *job, *n;
- BUG_ON(!cdma->running);
+ /* If CDMA is stopped, queue is cleared and we can return */
+ if (!cdma->running)
+ return;
/*
* Walk the sync queue, reading the sync point registers as necessary,
@@ -181,8 +193,8 @@ static void update_cdma_locked(struct nvhost_cdma *cdma)
/* Pop push buffer slots */
if (job->num_slots) {
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).pop_from);
- cdma_pb_op(cdma).pop_from(pb, job->num_slots);
+ BUG_ON(!cdma_pb_op().pop_from);
+ cdma_pb_op().pop_from(pb, job->num_slots);
if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
signal = true;
}
@@ -207,7 +219,6 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
{
u32 get_restart;
u32 syncpt_incrs;
- bool exec_ctxsave;
struct nvhost_job *job = NULL;
u32 syncpt_val;
@@ -274,7 +285,7 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
nvhost_job_dump(dev, job);
/* safe to use CPU to incr syncpts */
- cdma_op(cdma).timeout_cpu_incr(cdma,
+ cdma_op().timeout_cpu_incr(cdma,
job->first_get,
syncpt_incrs,
job->syncpt_end,
@@ -284,45 +295,10 @@ void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
}
dev_dbg(dev,
- "%s: GPU incr blocked interleaved ctx buffers\n",
- __func__);
-
- exec_ctxsave = false;
-
- /* setup GPU increments */
- list_for_each_entry_from(job, &cdma->sync_queue, list) {
- /* same context, increment in the pushbuffer */
- if (job->clientid == cdma->timeout.clientid) {
- /* won't need a timeout when replayed */
- job->timeout = 0;
-
- /* update buffer's syncpts in the pushbuffer */
- cdma_op(cdma).timeout_pb_incr(cdma,
- job->first_get,
- job->syncpt_incrs,
- job->num_slots,
- exec_ctxsave);
-
- exec_ctxsave = false;
- } else {
- dev_dbg(dev,
- "%s: switch to a different userctx\n",
- __func__);
- /*
- * If previous context was the timed out context
- * then clear its CTXSAVE in this slot.
- */
- exec_ctxsave = true;
- }
-
- nvhost_job_dump(dev, job);
- }
-
- dev_dbg(dev,
"%s: finished sync_queue modification\n", __func__);
/* roll back DMAGET and start up channel again */
- cdma_op(cdma).timeout_teardown_end(cdma, get_restart);
+ cdma_op().timeout_teardown_end(cdma, get_restart);
if (cdma->timeout.ctx)
cdma->timeout.ctx->has_timedout = true;
@@ -335,7 +311,7 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma)
{
int err;
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).init);
+ BUG_ON(!cdma_pb_op().init);
mutex_init(&cdma->lock);
sema_init(&cdma->sem, 0);
@@ -345,7 +321,7 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma)
cdma->running = false;
cdma->torndown = false;
- err = cdma_pb_op(cdma).init(pb);
+ err = cdma_pb_op().init(pb);
if (err)
return err;
return 0;
@@ -358,10 +334,10 @@ void nvhost_cdma_deinit(struct nvhost_cdma *cdma)
{
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).destroy);
+ BUG_ON(!cdma_pb_op().destroy);
BUG_ON(cdma->running);
- cdma_pb_op(cdma).destroy(pb);
- cdma_op(cdma).timeout_destroy(cdma);
+ cdma_pb_op().destroy(pb);
+ cdma_op().timeout_destroy(cdma);
}
/**
@@ -375,8 +351,8 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
/* init state on first submit with timeout value */
if (!cdma->timeout.initialized) {
int err;
- BUG_ON(!cdma_op(cdma).timeout_init);
- err = cdma_op(cdma).timeout_init(cdma,
+ BUG_ON(!cdma_op().timeout_init);
+ err = cdma_op().timeout_init(cdma,
job->syncpt_id);
if (err) {
mutex_unlock(&cdma->lock);
@@ -385,22 +361,58 @@ int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
}
}
if (!cdma->running) {
- BUG_ON(!cdma_op(cdma).start);
- cdma_op(cdma).start(cdma);
+ BUG_ON(!cdma_op().start);
+ cdma_op().start(cdma);
}
cdma->slots_free = 0;
cdma->slots_used = 0;
- cdma->first_get = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+ cdma->first_get = cdma_pb_op().putptr(&cdma->push_buffer);
return 0;
}
+static void trace_write_gather(struct nvhost_cdma *cdma,
+ struct nvmap_handle *handle,
+ u32 offset, u32 words)
+{
+ struct nvmap_handle_ref ref;
+ void *mem = NULL;
+
+ if (nvhost_debug_trace_cmdbuf) {
+ ref.handle = handle;
+ mem = nvmap_mmap(&ref);
+ if (IS_ERR_OR_NULL(mem))
+ mem = NULL;
+ };
+
+ if (mem) {
+ u32 i;
+ /*
+ * Write in batches of 128 as there seems to be a limit
+ * of how much you can output to ftrace at once.
+ */
+ for (i = 0; i < words; i += TRACE_MAX_LENGTH) {
+ trace_nvhost_cdma_push_gather(
+ cdma_to_channel(cdma)->dev->name,
+ (u32)handle,
+ min(words - i, TRACE_MAX_LENGTH),
+ offset + i * sizeof(u32),
+ mem);
+ }
+ nvmap_munmap(&ref, mem);
+ }
+}
+
/**
* Push two words into a push buffer slot
* Blocks as necessary if the push buffer is full.
*/
void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
{
- nvhost_cdma_push_gather(cdma, NULL, NULL, op1, op2);
+ if (nvhost_debug_trace_cmdbuf)
+ trace_nvhost_cdma_push(cdma_to_channel(cdma)->dev->name,
+ op1, op2);
+
+ nvhost_cdma_push_gather(cdma, NULL, NULL, 0, op1, op2);
}
/**
@@ -409,20 +421,26 @@ void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
*/
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2)
+ struct nvmap_handle *handle,
+ u32 offset, u32 op1, u32 op2)
{
u32 slots_free = cdma->slots_free;
struct push_buffer *pb = &cdma->push_buffer;
- BUG_ON(!cdma_pb_op(cdma).push_to);
- BUG_ON(!cdma_op(cdma).kick);
+
+ BUG_ON(!cdma_pb_op().push_to);
+ BUG_ON(!cdma_op().kick);
+
+ if (handle)
+ trace_write_gather(cdma, handle, offset, op1 & 0xffff);
+
if (slots_free == 0) {
- cdma_op(cdma).kick(cdma);
+ cdma_op().kick(cdma);
slots_free = nvhost_cdma_wait_locked(cdma,
CDMA_EVENT_PUSH_BUFFER_SPACE);
}
cdma->slots_free = slots_free - 1;
cdma->slots_used++;
- cdma_pb_op(cdma).push_to(pb, client, handle, op1, op2);
+ cdma_pb_op().push_to(pb, client, handle, op1, op2);
}
/**
@@ -436,8 +454,8 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
{
bool was_idle = list_empty(&cdma->sync_queue);
- BUG_ON(!cdma_op(cdma).kick);
- cdma_op(cdma).kick(cdma);
+ BUG_ON(!cdma_op().kick);
+ cdma_op().kick(cdma);
BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h
index 9cb9b82..e6f5117 100644
--- a/drivers/video/tegra/host/nvhost_cdma.h
+++ b/drivers/video/tegra/host/nvhost_cdma.h
@@ -25,11 +25,9 @@
#include <linux/semaphore.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/list.h>
-#include "nvhost_acm.h"
-
struct nvhost_syncpt;
struct nvhost_userctx_timeout;
struct nvhost_job;
@@ -97,7 +95,6 @@ struct nvhost_cdma {
unsigned int first_get; /* DMAGET value, where submit begins */
unsigned int last_put; /* last value written to DMAPUT */
struct push_buffer push_buffer; /* channel's push buffer */
- struct syncpt_buffer syncpt_buffer; /* syncpt incr buffer */
struct list_head sync_queue; /* job queue */
struct buffer_timeout timeout; /* channel's timeout state/wq */
bool running;
@@ -106,20 +103,17 @@ struct nvhost_cdma {
#define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
#define cdma_to_dev(cdma) nvhost_get_host(cdma_to_channel(cdma)->dev)
-#define cdma_op(cdma) (cdma_to_dev(cdma)->op.cdma)
#define cdma_to_nvmap(cdma) ((cdma_to_dev(cdma))->nvmap)
#define pb_to_cdma(pb) container_of(pb, struct nvhost_cdma, push_buffer)
-#define cdma_pb_op(cdma) (cdma_to_dev(cdma)->op.push_buffer)
int nvhost_cdma_init(struct nvhost_cdma *cdma);
void nvhost_cdma_deinit(struct nvhost_cdma *cdma);
void nvhost_cdma_stop(struct nvhost_cdma *cdma);
int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job);
void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2);
-#define NVHOST_CDMA_PUSH_GATHER_CTXSAVE 0xffffffff
void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
struct nvmap_client *client,
- struct nvmap_handle *handle, u32 op1, u32 op2);
+ struct nvmap_handle *handle, u32 offset, u32 op1, u32 op2);
void nvhost_cdma_end(struct nvhost_cdma *cdma,
struct nvhost_job *job);
void nvhost_cdma_update(struct nvhost_cdma *cdma);
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
index afbac6f..ef8886f 100644
--- a/drivers/video/tegra/host/nvhost_channel.c
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -20,13 +20,14 @@
#include "nvhost_channel.h"
#include "dev.h"
+#include "nvhost_acm.h"
#include "nvhost_job.h"
+#include "chip_support.h"
+
#include <trace/events/nvhost.h>
#include <linux/nvhost_ioctl.h>
#include <linux/slab.h>
-#include <linux/platform_device.h>
-
#define NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT 50
int nvhost_channel_init(struct nvhost_channel *ch,
@@ -36,7 +37,7 @@ int nvhost_channel_init(struct nvhost_channel *ch,
struct nvhost_device *ndev;
/* Link nvhost_device to nvhost_channel */
- err = host_channel_op(dev).init(ch, dev, index);
+ err = channel_op().init(ch, dev, index);
if (err < 0) {
dev_err(&dev->dev->dev, "failed to init channel %d\n",
index);
@@ -57,16 +58,18 @@ int nvhost_channel_submit(struct nvhost_job *job)
(void)nvhost_cdma_flush(&job->ch->cdma,
NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
- return channel_op(job->ch).submit(job);
+ return channel_op().submit(job);
}
struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
{
int err = 0;
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
+
mutex_lock(&ch->reflock);
if (ch->refcount == 0) {
- if (ch->dev->init)
- ch->dev->init(ch->dev);
+ if (drv->init)
+ drv->init(ch->dev);
err = nvhost_cdma_init(&ch->cdma);
} else if (ch->dev->exclusive) {
err = -EBUSY;
@@ -85,7 +88,7 @@ struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
{
- BUG_ON(!channel_cdma_op(ch).stop);
+ BUG_ON(!channel_cdma_op().stop);
if (ctx) {
mutex_lock(&ch->submitlock);
@@ -100,7 +103,7 @@ void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
mutex_lock(&ch->reflock);
if (ch->refcount == 1) {
- channel_cdma_op(ch).stop(&ch->cdma);
+ channel_cdma_op().stop(&ch->cdma);
nvhost_cdma_deinit(&ch->cdma);
nvhost_module_suspend(ch->dev);
}
@@ -113,14 +116,40 @@ int nvhost_channel_suspend(struct nvhost_channel *ch)
int ret = 0;
mutex_lock(&ch->reflock);
- BUG_ON(!channel_cdma_op(ch).stop);
+ BUG_ON(!channel_cdma_op().stop);
if (ch->refcount) {
ret = nvhost_module_suspend(ch->dev);
if (!ret)
- channel_cdma_op(ch).stop(&ch->cdma);
+ channel_cdma_op().stop(&ch->cdma);
}
mutex_unlock(&ch->reflock);
return ret;
}
+
+struct nvhost_channel *nvhost_alloc_channel_internal(int chindex,
+ int max_channels, int *current_channel_count)
+{
+ struct nvhost_channel *ch = NULL;
+
+ if ( (chindex > max_channels) ||
+ ( (*current_channel_count + 1) > max_channels) )
+ return NULL;
+ else {
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+ if (ch == NULL)
+ return NULL;
+ else {
+ (*current_channel_count)++;
+ return ch;
+ }
+ }
+}
+
+void nvhost_free_channel_internal(struct nvhost_channel *ch,
+ int *current_channel_count)
+{
+ kfree(ch);
+ (*current_channel_count)--;
+}
diff --git a/drivers/video/tegra/host/nvhost_channel.h b/drivers/video/tegra/host/nvhost_channel.h
index 7b946c8..eac5173 100644
--- a/drivers/video/tegra/host/nvhost_channel.h
+++ b/drivers/video/tegra/host/nvhost_channel.h
@@ -21,22 +21,20 @@
#ifndef __NVHOST_CHANNEL_H
#define __NVHOST_CHANNEL_H
-#include "nvhost_cdma.h"
-#include "nvhost_acm.h"
-#include "nvhost_hwctx.h"
-#include "nvhost_job.h"
-
#include <linux/cdev.h>
#include <linux/io.h>
+#include "nvhost_cdma.h"
-#define NVHOST_MAX_WAIT_CHECKS 256
-#define NVHOST_MAX_GATHERS 512
-#define NVHOST_MAX_HANDLES 1280
-#define NVHOST_MAX_POWERGATE_IDS 2
+#define NVHOST_MAX_WAIT_CHECKS 256
+#define NVHOST_MAX_GATHERS 512
+#define NVHOST_MAX_HANDLES 1280
+#define NVHOST_MAX_POWERGATE_IDS 2
struct nvhost_master;
struct nvhost_waitchk;
struct nvhost_device;
+struct nvhost_channel;
+struct nvhost_hwctx;
struct nvhost_channel_gather {
u32 words;
@@ -60,8 +58,7 @@ struct nvhost_channel {
struct nvhost_cdma cdma;
};
-int nvhost_channel_init(
- struct nvhost_channel *ch,
+int nvhost_channel_init(struct nvhost_channel *ch,
struct nvhost_master *dev, int index);
int nvhost_channel_submit(struct nvhost_job *job);
@@ -70,17 +67,17 @@ struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch);
void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx);
int nvhost_channel_suspend(struct nvhost_channel *ch);
-#define channel_cdma_op(ch) (nvhost_get_host(ch->dev)->op.cdma)
-#define channel_op(ch) (nvhost_get_host(ch->dev)->op.channel)
-#define host_channel_op(host) (host->op.channel)
-
int nvhost_channel_drain_read_fifo(void __iomem *chan_regs,
u32 *ptr, unsigned int count, unsigned int *pending);
-int nvhost_channel_read_3d_reg(
- struct nvhost_channel *channel,
+int nvhost_channel_read_3d_reg(struct nvhost_channel *channel,
struct nvhost_hwctx *hwctx,
- u32 offset,
- u32 *value);
+ u32 offset, u32 *value);
+
+struct nvhost_channel *nvhost_alloc_channel_internal(int chindex,
+ int max_channels, int *current_channel_count);
+
+void nvhost_free_channel_internal(struct nvhost_channel *ch,
+ int *current_channel_count);
#endif
diff --git a/drivers/video/tegra/host/nvhost_hwctx.h b/drivers/video/tegra/host/nvhost_hwctx.h
index 02a3976..75ed0be 100644
--- a/drivers/video/tegra/host/nvhost_hwctx.h
+++ b/drivers/video/tegra/host/nvhost_hwctx.h
@@ -25,7 +25,7 @@
#include <linux/kref.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
struct nvhost_channel;
struct nvhost_cdma;
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index 7c4bdc7..ba821f6 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -20,14 +20,13 @@
#include "nvhost_intr.h"
#include "dev.h"
+#include "nvhost_acm.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <trace/events/nvhost.h>
-
-
-
-
+#include "nvhost_channel.h"
+#include "nvhost_hwctx.h"
/*** Wait list management ***/
@@ -116,11 +115,11 @@ void reset_threshold_interrupt(struct nvhost_intr *intr,
{
u32 thresh = list_first_entry(head,
struct nvhost_waitlist, list)->thresh;
- BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
- intr_op(intr).enable_syncpt_intr));
+ BUG_ON(!(intr_op().set_syncpt_threshold &&
+ intr_op().enable_syncpt_intr));
- intr_op(intr).set_syncpt_threshold(intr, id, thresh);
- intr_op(intr).enable_syncpt_intr(intr, id);
+ intr_op().set_syncpt_threshold(intr, id, thresh);
+ intr_op().enable_syncpt_intr(intr, id);
}
@@ -264,8 +263,8 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
BUG_ON(waiter == NULL);
- BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
- intr_op(intr).enable_syncpt_intr));
+ BUG_ON(!(intr_op().set_syncpt_threshold &&
+ intr_op().enable_syncpt_intr));
/* initialize a new waiter */
INIT_LIST_HEAD(&waiter->list);
@@ -288,8 +287,8 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
spin_unlock(&syncpt->lock);
mutex_lock(&intr->mutex);
- BUG_ON(!(intr_op(intr).request_syncpt_irq));
- err = intr_op(intr).request_syncpt_irq(syncpt);
+ BUG_ON(!(intr_op().request_syncpt_irq));
+ err = intr_op().request_syncpt_irq(syncpt);
mutex_unlock(&intr->mutex);
if (err) {
@@ -304,11 +303,11 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
if (add_waiter_to_queue(waiter, &syncpt->wait_head)) {
/* added at head of list - new threshold value */
- intr_op(intr).set_syncpt_threshold(intr, id, thresh);
+ intr_op().set_syncpt_threshold(intr, id, thresh);
/* added as first waiter - enable interrupt */
if (queue_was_empty)
- intr_op(intr).enable_syncpt_intr(intr, id);
+ intr_op().enable_syncpt_intr(intr, id);
}
spin_unlock(&syncpt->lock);
@@ -347,6 +346,7 @@ int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync)
u32 nb_pts = host->syncpt.nb_pts;
mutex_init(&intr->mutex);
+ intr_op().init_host_sync(intr);
intr->host_general_irq = irq_gen;
intr->host_general_irq_requested = false;
@@ -374,17 +374,17 @@ void nvhost_intr_deinit(struct nvhost_intr *intr)
void nvhost_intr_start(struct nvhost_intr *intr, u32 hz)
{
- BUG_ON(!(intr_op(intr).init_host_sync &&
- intr_op(intr).set_host_clocks_per_usec &&
- intr_op(intr).request_host_general_irq));
+ BUG_ON(!(intr_op().init_host_sync &&
+ intr_op().set_host_clocks_per_usec &&
+ intr_op().request_host_general_irq));
mutex_lock(&intr->mutex);
- intr_op(intr).init_host_sync(intr);
- intr_op(intr).set_host_clocks_per_usec(intr,
+ intr_op().init_host_sync(intr);
+ intr_op().set_host_clocks_per_usec(intr,
(hz + 1000000 - 1)/1000000);
- intr_op(intr).request_host_general_irq(intr);
+ intr_op().request_host_general_irq(intr);
mutex_unlock(&intr->mutex);
}
@@ -395,12 +395,12 @@ void nvhost_intr_stop(struct nvhost_intr *intr)
struct nvhost_intr_syncpt *syncpt;
u32 nb_pts = intr_to_dev(intr)->syncpt.nb_pts;
- BUG_ON(!(intr_op(intr).disable_all_syncpt_intrs &&
- intr_op(intr).free_host_general_irq));
+ BUG_ON(!(intr_op().disable_all_syncpt_intrs &&
+ intr_op().free_host_general_irq));
mutex_lock(&intr->mutex);
- intr_op(intr).disable_all_syncpt_intrs(intr);
+ intr_op().disable_all_syncpt_intrs(intr);
for (id = 0, syncpt = intr->syncpt;
id < nb_pts;
@@ -422,7 +422,7 @@ void nvhost_intr_stop(struct nvhost_intr *intr)
free_syncpt_irq(syncpt);
}
- intr_op(intr).free_host_general_irq(intr);
+ intr_op().free_host_general_irq(intr);
mutex_unlock(&intr->mutex);
}
diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h
index 26ab04e..eea9d83 100644
--- a/drivers/video/tegra/host/nvhost_intr.h
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -74,7 +74,6 @@ struct nvhost_intr {
bool host_general_irq_requested;
};
#define intr_to_dev(x) container_of(x, struct nvhost_master, intr)
-#define intr_op(intr) (intr_to_dev(intr)->op.intr)
#define intr_syncpt_to_intr(is) (is->intr)
/**
diff --git a/drivers/video/tegra/host/nvhost_job.c b/drivers/video/tegra/host/nvhost_job.c
index df7a62d..71f2ab0e 100644
--- a/drivers/video/tegra/host/nvhost_job.c
+++ b/drivers/video/tegra/host/nvhost_job.c
@@ -22,9 +22,10 @@
#include <linux/kref.h>
#include <linux/err.h>
#include <linux/vmalloc.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvhost_channel.h"
#include "nvhost_job.h"
+#include "nvhost_hwctx.h"
#include "dev.h"
/* Magic to use to fill freed handle slots */
@@ -73,7 +74,7 @@ static int alloc_gathers(struct nvhost_job *job,
gather_size(num_cmdbufs),
32, NVMAP_HANDLE_CACHEABLE, 0);
if (IS_ERR_OR_NULL(job->gather_mem)) {
- err = PTR_ERR(job->gather_mem);
+ err = job->gather_mem ? PTR_ERR(job->gather_mem) : -ENOMEM;
job->gather_mem = NULL;
goto error;
}
@@ -82,7 +83,7 @@ static int alloc_gathers(struct nvhost_job *job,
/* Map memory to kernel */
job->gathers = nvmap_mmap(job->gather_mem);
if (IS_ERR_OR_NULL(job->gathers)) {
- err = PTR_ERR(job->gathers);
+ err = job->gathers ? PTR_ERR(job->gathers) : -ENOMEM;
job->gathers = NULL;
goto error;
}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 13ad0fc..4835d22 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -21,10 +21,11 @@
#include <linux/nvhost_ioctl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <trace/events/nvhost.h>
#include "nvhost_syncpt.h"
+#include "nvhost_acm.h"
#include "dev.h"
-#define MAX_STUCK_CHECK_COUNT 15
#define MAX_SYNCPT_LENGTH 5
/* Name of sysfs node for min and max value */
static const char *min_name = "min";
@@ -36,12 +37,12 @@ static const char *max_name = "max";
void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
{
u32 i;
- BUG_ON(!(syncpt_op(sp).reset && syncpt_op(sp).reset_wait_base));
+ BUG_ON(!(syncpt_op().reset && syncpt_op().reset_wait_base));
for (i = 0; i < sp->nb_pts; i++)
- syncpt_op(sp).reset(sp, i);
+ syncpt_op().reset(sp, i);
for (i = 0; i < sp->nb_bases; i++)
- syncpt_op(sp).reset_wait_base(sp, i);
+ syncpt_op().reset_wait_base(sp, i);
wmb();
}
@@ -51,17 +52,17 @@ void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
void nvhost_syncpt_save(struct nvhost_syncpt *sp)
{
u32 i;
- BUG_ON(!(syncpt_op(sp).update_min && syncpt_op(sp).read_wait_base));
+ BUG_ON(!(syncpt_op().update_min && syncpt_op().read_wait_base));
for (i = 0; i < sp->nb_pts; i++) {
if (client_managed(i))
- syncpt_op(sp).update_min(sp, i);
+ syncpt_op().update_min(sp, i);
else
BUG_ON(!nvhost_syncpt_min_eq_max(sp, i));
}
for (i = 0; i < sp->nb_bases; i++)
- syncpt_op(sp).read_wait_base(sp, i);
+ syncpt_op().read_wait_base(sp, i);
}
/**
@@ -69,9 +70,14 @@ void nvhost_syncpt_save(struct nvhost_syncpt *sp)
*/
u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
{
- BUG_ON(!syncpt_op(sp).update_min);
+ u32 val;
+
+ BUG_ON(!syncpt_op().update_min);
- return syncpt_op(sp).update_min(sp, id);
+ return syncpt_op().update_min(sp, id);
+ trace_nvhost_syncpt_update_min(id, val);
+
+ return val;
}
/**
@@ -80,9 +86,9 @@ u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
{
u32 val;
- BUG_ON(!syncpt_op(sp).update_min);
+ BUG_ON(!syncpt_op().update_min);
nvhost_module_busy(syncpt_to_dev(sp)->dev);
- val = syncpt_op(sp).update_min(sp, id);
+ val = syncpt_op().update_min(sp, id);
nvhost_module_idle(syncpt_to_dev(sp)->dev);
return val;
}
@@ -93,9 +99,9 @@ u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
{
u32 val;
- BUG_ON(!syncpt_op(sp).read_wait_base);
+ BUG_ON(!syncpt_op().read_wait_base);
nvhost_module_busy(syncpt_to_dev(sp)->dev);
- syncpt_op(sp).read_wait_base(sp, id);
+ syncpt_op().read_wait_base(sp, id);
val = sp->base_val[id];
nvhost_module_idle(syncpt_to_dev(sp)->dev);
return val;
@@ -107,8 +113,8 @@ u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
*/
void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
{
- BUG_ON(!syncpt_op(sp).cpu_incr);
- syncpt_op(sp).cpu_incr(sp, id);
+ BUG_ON(!syncpt_op().cpu_incr);
+ syncpt_op().cpu_incr(sp, id);
}
/**
@@ -149,7 +155,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
nvhost_module_busy(syncpt_to_dev(sp)->dev);
/* try to read from register */
- val = syncpt_op(sp).update_min(sp, id);
+ val = syncpt_op().update_min(sp, id);
if (nvhost_syncpt_is_expired(sp, id, thresh)) {
if (value)
*value = val;
@@ -198,20 +204,19 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
}
if (timeout != NVHOST_NO_TIMEOUT)
timeout -= check;
- if (timeout) {
+ if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) {
dev_warn(&syncpt_to_dev(sp)->dev->dev,
"%s: syncpoint id %d (%s) stuck waiting %d, timeout=%d\n",
- current->comm, id, syncpt_op(sp).name(sp, id),
+ current->comm, id, syncpt_op().name(sp, id),
thresh, timeout);
- syncpt_op(sp).debug(sp);
- if (check_count > MAX_STUCK_CHECK_COUNT) {
+ syncpt_op().debug(sp);
+ if (check_count == MAX_STUCK_CHECK_COUNT) {
if (low_timeout) {
dev_warn(&syncpt_to_dev(sp)->dev->dev,
"is timeout %d too low?\n",
low_timeout);
}
nvhost_debug_dump(syncpt_to_dev(sp));
- BUG();
}
check_count++;
}
@@ -287,7 +292,7 @@ bool nvhost_syncpt_is_expired(
void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
{
- syncpt_op(sp).debug(sp);
+ syncpt_op().debug(sp);
}
int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
@@ -296,7 +301,7 @@ int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
u32 reg;
nvhost_module_busy(host->dev);
- reg = syncpt_op(sp).mutex_try_lock(sp, idx);
+ reg = syncpt_op().mutex_try_lock(sp, idx);
if (reg) {
nvhost_module_idle(host->dev);
return -EBUSY;
@@ -307,7 +312,7 @@ int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx)
{
- syncpt_op(sp).mutex_unlock(sp, idx);
+ syncpt_op().mutex_unlock(sp, idx);
nvhost_module_idle(syncpt_to_dev(sp)->dev);
atomic_dec(&sp->lock_counts[idx]);
}
@@ -319,7 +324,7 @@ int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
struct nvhost_waitchk *wait,
int num_waitchk)
{
- return syncpt_op(sp).wait_check(sp, nvmap,
+ return syncpt_op().wait_check(sp, nvmap,
waitchk_mask, wait, num_waitchk);
}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h
index b71cb3e..b770ed9 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.h
+++ b/drivers/video/tegra/host/nvhost_syncpt.h
@@ -24,12 +24,9 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/nvhost.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/atomic.h>
-struct nvhost_syncpt;
-struct nvhost_waitchk;
-
/* host managed and invalid syncpt id */
#define NVSYNCPT_GRAPHICS_HOST (0)
#define NVSYNCPT_INVALID (-1)
@@ -59,9 +56,8 @@ void nvhost_syncpt_deinit(struct nvhost_syncpt *);
#define client_managed(id) (BIT(id) & sp->client_managed)
#define syncpt_to_dev(sp) container_of(sp, struct nvhost_master, syncpt)
-#define syncpt_op(sp) (syncpt_to_dev(sp)->op.syncpt)
-#define SYNCPT_CHECK_PERIOD (2*HZ)
-
+#define SYNCPT_CHECK_PERIOD (2 * HZ)
+#define MAX_STUCK_CHECK_COUNT 15
/**
* Updates the value sent to hardware.
@@ -151,6 +147,7 @@ static inline int nvhost_syncpt_wait(struct nvhost_syncpt *sp, u32 id, u32 thres
* @param: wait - start of filled in array of waitchk structs
* @param: waitend - end ptr (one beyond last valid waitchk)
*/
+struct nvhost_waitchk;
int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
struct nvmap_client *nvmap,
u32 mask,
diff --git a/drivers/video/tegra/host/t20/t20.c b/drivers/video/tegra/host/t20/t20.c
index 24ddedc..f6713d8 100644
--- a/drivers/video/tegra/host/t20/t20.c
+++ b/drivers/video/tegra/host/t20/t20.c
@@ -19,17 +19,19 @@
*/
#include <linux/slab.h>
+#include <linux/nvhost_ioctl.h>
#include <mach/powergate.h>
#include "dev.h"
#include "t20.h"
-#include "host1x/host1x_channel.h"
#include "host1x/host1x_syncpt.h"
#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_cdma.h"
#include "gr3d/gr3d.h"
#include "gr3d/gr3d_t20.h"
#include "mpe/mpe.h"
#include "nvhost_hwctx.h"
+#include "nvhost_channel.h"
+#include "host1x/host1x_channel.h"
+#include "host1x/host1x_cdma.h"
#define NVMODMUTEX_2D_FULL (1)
#define NVMODMUTEX_2D_SIMPLE (2)
@@ -41,7 +43,9 @@
#define NVMODMUTEX_VI (8)
#define NVMODMUTEX_DSI (9)
-#define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+#define T20_NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+
+static int t20_num_alloc_channels = 0;
struct nvhost_device t20_devices[] = {
{
@@ -60,15 +64,13 @@ struct nvhost_device t20_devices[] = {
},
{
/* channel 1 */
- .name = "gr3d",
+ .name = "gr3d01",
.id = -1,
.index = 1,
.syncpts = BIT(NVSYNCPT_3D),
.waitbases = BIT(NVWAITBASE_3D),
.modulemutexes = BIT(NVMODMUTEX_3D),
.class = NV_GRAPHICS_3D_CLASS_ID,
- .prepare_poweroff = nvhost_gr3d_prepare_power_off,
- .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
.clocks = {{"gr3d", UINT_MAX}, {"emc", UINT_MAX}, {} },
.powergate_ids = {TEGRA_POWERGATE_3D, -1},
NVHOST_DEFAULT_CLOCKGATE_DELAY,
@@ -117,7 +119,7 @@ struct nvhost_device t20_devices[] = {
},
{
/* channel 5 */
- .name = "mpe",
+ .name = "mpe01",
.id = -1,
.index = 5,
.syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
@@ -126,8 +128,6 @@ struct nvhost_device t20_devices[] = {
.class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
.waitbasesync = true,
.keepalive = true,
- .prepare_poweroff = nvhost_mpe_prepare_power_off,
- .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
.clocks = { {"mpe", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = {TEGRA_POWERGATE_MPE, -1},
@@ -161,9 +161,10 @@ static inline int t20_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
unsigned long waitbases = ch->dev->waitbases;
u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
- if (ch->dev->alloc_hwctx_handler) {
- ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
+ if (drv->alloc_hwctx_handler) {
+ ch->ctxhandler = drv->alloc_hwctx_handler(syncpt,
waitbase, ch);
if (!ch->ctxhandler)
err = -ENOMEM;
@@ -184,50 +185,64 @@ static int t20_channel_init(struct nvhost_channel *ch,
return t20_nvhost_hwctx_handler_init(ch);
}
-int nvhost_init_t20_channel_support(struct nvhost_master *host)
+int nvhost_init_t20_channel_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
- host->nb_channels = NVHOST_NUMCHANNELS;
-
- host->op.channel.init = t20_channel_init;
- host->op.channel.submit = host1x_channel_submit;
- host->op.channel.read3dreg = host1x_channel_read_3d_reg;
+ op->channel.init = t20_channel_init;
+ op->channel.submit = host1x_channel_submit;
+ op->channel.read3dreg = host1x_channel_read_3d_reg;
return 0;
}
-struct nvhost_device *t20_get_nvhost_device(struct nvhost_master *host,
- char *name)
+static void t20_free_nvhost_channel(struct nvhost_channel *ch)
+{
+ nvhost_free_channel_internal(ch, &t20_num_alloc_channels);
+}
+
+static struct nvhost_channel *t20_alloc_nvhost_channel(int chindex)
+{
+ return nvhost_alloc_channel_internal(chindex,
+ T20_NVHOST_NUMCHANNELS, &t20_num_alloc_channels);
+}
+
+struct nvhost_device *t20_get_nvhost_device(char *name)
{
int i;
- for (i = 0; i < host->nb_channels; i++) {
- if (strcmp(t20_devices[i].name, name) == 0)
+ for (i = 0; i < ARRAY_SIZE(t20_devices); i++) {
+ if (strncmp(t20_devices[i].name, name, strlen(name)) == 0)
return &t20_devices[i];
}
return NULL;
}
-int nvhost_init_t20_support(struct nvhost_master *host)
+int nvhost_init_t20_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
int err;
/* don't worry about cleaning up on failure... "remove" does it. */
- err = nvhost_init_t20_channel_support(host);
+ err = nvhost_init_t20_channel_support(host, op);
if (err)
return err;
- err = host1x_init_cdma_support(host);
+ err = host1x_init_cdma_support(op);
if (err)
return err;
- err = nvhost_init_t20_debug_support(host);
+ err = nvhost_init_t20_debug_support(op);
if (err)
return err;
- err = host1x_init_syncpt_support(host);
+ err = host1x_init_syncpt_support(host, op);
if (err)
return err;
- err = nvhost_init_t20_intr_support(host);
+ err = nvhost_init_t20_intr_support(op);
if (err)
return err;
- host->op.nvhost_dev.get_nvhost_device = t20_get_nvhost_device;
+
+ op->nvhost_dev.get_nvhost_device = t20_get_nvhost_device;
+ op->nvhost_dev.alloc_nvhost_channel = t20_alloc_nvhost_channel;
+ op->nvhost_dev.free_nvhost_channel = t20_free_nvhost_channel;
+
return 0;
}
diff --git a/drivers/video/tegra/host/t20/t20.h b/drivers/video/tegra/host/t20/t20.h
index 93555a5..456d3ae1 100644
--- a/drivers/video/tegra/host/t20/t20.h
+++ b/drivers/video/tegra/host/t20/t20.h
@@ -22,12 +22,15 @@
struct nvhost_master;
struct nvhost_module;
+struct nvhost_chip_support;
-int nvhost_init_t20_channel_support(struct nvhost_master *);
-int nvhost_init_t20_debug_support(struct nvhost_master *);
+int nvhost_init_t20_channel_support(struct nvhost_master *,
+ struct nvhost_chip_support *);
+int nvhost_init_t20_debug_support(struct nvhost_chip_support *);
int nvhost_init_t20_syncpt_support(struct nvhost_master *);
-int nvhost_init_t20_intr_support(struct nvhost_master *);
-int nvhost_init_t20_support(struct nvhost_master *host);
+int nvhost_init_t20_intr_support(struct nvhost_chip_support *);
+int nvhost_init_t20_support(struct nvhost_master *,
+ struct nvhost_chip_support *);
int nvhost_t20_save_context(struct nvhost_module *mod, u32 syncpt_id);
#endif /* _NVHOST_T20_H_ */
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
index 8a8b1f4..257ba08 100644
--- a/drivers/video/tegra/host/t30/t30.c
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -19,19 +19,21 @@
*/
#include <linux/mutex.h>
+#include <linux/nvhost_ioctl.h>
#include <mach/powergate.h>
#include <mach/iomap.h>
#include "dev.h"
#include "t20/t20.h"
#include "t30.h"
#include "gr3d/gr3d.h"
-#include "mpe/mpe.h"
#include "gr3d/gr3d_t30.h"
#include "gr3d/scale3d.h"
+#include "mpe/mpe.h"
#include "host1x/host1x_hardware.h"
-#include "host1x/host1x_cdma.h"
#include "host1x/host1x_syncpt.h"
#include "chip_support.h"
+#include "nvhost_channel.h"
+#include "host1x/host1x_cdma.h"
#define NVMODMUTEX_2D_FULL (1)
#define NVMODMUTEX_2D_SIMPLE (2)
@@ -45,6 +47,10 @@
#define NVHOST_CHANNEL_BASE 0
+#define T30_NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+
+static int t30_num_alloc_channels = 0;
+
struct nvhost_device t30_devices[] = {
{
/* channel 0 */
@@ -62,27 +68,21 @@ struct nvhost_device t30_devices[] = {
},
{
/* channel 1 */
- .name = "gr3d",
+ .name = "gr3d02",
.id = -1,
.index = 1,
.syncpts = BIT(NVSYNCPT_3D),
.waitbases = BIT(NVWAITBASE_3D),
.modulemutexes = BIT(NVMODMUTEX_3D),
.class = NV_GRAPHICS_3D_CLASS_ID,
- .prepare_poweroff = nvhost_gr3d_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,
- .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
.clocks = { {"gr3d", UINT_MAX},
{"gr3d2", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = { TEGRA_POWERGATE_3D,
TEGRA_POWERGATE_3D1 },
NVHOST_DEFAULT_CLOCKGATE_DELAY,
- .can_powergate = false,
+ .can_powergate = true,
+ .powerup_reset = true,
.powergate_delay = 250,
.moduleid = NVHOST_MODULE_NONE,
},
@@ -95,7 +95,7 @@ struct nvhost_device t30_devices[] = {
.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),
- .clocks = { {"gr2d", 0},
+ .clocks = { {"gr2d", UINT_MAX},
{"epp", 0},
{"emc", 300000000} },
NVHOST_MODULE_NO_POWERGATE_IDS,
@@ -129,7 +129,7 @@ struct nvhost_device t30_devices[] = {
},
{
/* channel 5 */
- .name = "mpe",
+ .name = "mpe02",
.id = -1,
.index = 5,
.syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
@@ -138,8 +138,6 @@ struct nvhost_device t30_devices[] = {
.class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
.waitbasesync = true,
.keepalive = true,
- .prepare_poweroff = nvhost_mpe_prepare_power_off,
- .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
.clocks = { {"mpe", UINT_MAX},
{"emc", UINT_MAX} },
.powergate_ids = {TEGRA_POWERGATE_MPE, -1},
@@ -167,9 +165,10 @@ static inline int t30_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
unsigned long waitbases = ch->dev->waitbases;
u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
+ struct nvhost_driver *drv = to_nvhost_driver(ch->dev->dev.driver);
- if (ch->dev->alloc_hwctx_handler) {
- ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
+ if (drv->alloc_hwctx_handler) {
+ ch->ctxhandler = drv->alloc_hwctx_handler(syncpt,
waitbase, ch);
if (!ch->ctxhandler)
err = -ENOMEM;
@@ -198,54 +197,71 @@ static int t30_channel_init(struct nvhost_channel *ch,
return t30_nvhost_hwctx_handler_init(ch);
}
-int nvhost_init_t30_channel_support(struct nvhost_master *host)
+int nvhost_init_t30_channel_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
- int result = nvhost_init_t20_channel_support(host);
- host->op.channel.init = t30_channel_init;
+ int result = nvhost_init_t20_channel_support(host, op);
+ op->channel.init = t30_channel_init;
return result;
}
-int nvhost_init_t30_debug_support(struct nvhost_master *host)
+
+int nvhost_init_t30_debug_support(struct nvhost_chip_support *op)
{
- nvhost_init_t20_debug_support(host);
- host->op.debug.debug_init = nvhost_scale3d_debug_init;
+ nvhost_init_t20_debug_support(op);
+ op->debug.debug_init = nvhost_scale3d_debug_init;
return 0;
}
-struct nvhost_device *t30_get_nvhost_device(struct nvhost_master *host,
- char *name)
+static void t30_free_nvhost_channel(struct nvhost_channel *ch)
+{
+ nvhost_free_channel_internal(ch, &t30_num_alloc_channels);
+}
+
+static struct nvhost_channel *t30_alloc_nvhost_channel(int chindex)
+{
+ return nvhost_alloc_channel_internal(chindex,
+ T30_NVHOST_NUMCHANNELS, &t30_num_alloc_channels);
+}
+
+struct nvhost_device *t30_get_nvhost_device(char *name)
{
int i;
- for (i = 0; i < host->nb_channels; i++) {
- if (strcmp(t30_devices[i].name, name) == 0)
+ for (i = 0; i < ARRAY_SIZE(t30_devices); i++) {
+ if (strncmp(t30_devices[i].name, name, strlen(name)) == 0)
return &t30_devices[i];
}
return NULL;
}
-int nvhost_init_t30_support(struct nvhost_master *host)
+int nvhost_init_t30_support(struct nvhost_master *host,
+ struct nvhost_chip_support *op)
{
int err;
/* don't worry about cleaning up on failure... "remove" does it. */
- err = nvhost_init_t30_channel_support(host);
+ err = nvhost_init_t30_channel_support(host, op);
if (err)
return err;
- err = host1x_init_cdma_support(host);
+ err = host1x_init_cdma_support(op);
if (err)
return err;
- err = nvhost_init_t30_debug_support(host);
+ err = nvhost_init_t30_debug_support(op);
if (err)
return err;
- err = host1x_init_syncpt_support(host);
+ err = host1x_init_syncpt_support(host, op);
if (err)
return err;
- err = nvhost_init_t20_intr_support(host);
+ err = nvhost_init_t20_intr_support(op);
if (err)
return err;
- host->op.nvhost_dev.get_nvhost_device = t30_get_nvhost_device;
+
+ op->nvhost_dev.get_nvhost_device = t30_get_nvhost_device;
+ op->nvhost_dev.alloc_nvhost_channel = t30_alloc_nvhost_channel;
+ op->nvhost_dev.free_nvhost_channel = t30_free_nvhost_channel;
+
return 0;
}
diff --git a/drivers/video/tegra/host/t30/t30.h b/drivers/video/tegra/host/t30/t30.h
index 0446dbd1..e4db97b 100644
--- a/drivers/video/tegra/host/t30/t30.h
+++ b/drivers/video/tegra/host/t30/t30.h
@@ -21,9 +21,12 @@
#define _NVHOST_T30_H_
struct nvhost_master;
+struct nvhost_chip_support;
-int nvhost_init_t30_channel_support(struct nvhost_master *);
-int nvhost_init_t30_debug_support(struct nvhost_master *);
-int nvhost_init_t30_support(struct nvhost_master *host);
+int nvhost_init_t30_channel_support(struct nvhost_master *,
+ struct nvhost_chip_support *);
+int nvhost_init_t30_debug_support(struct nvhost_chip_support *);
+int nvhost_init_t30_support(struct nvhost_master *host,
+ struct nvhost_chip_support *);
#endif /* _NVHOST_T30_H_ */
diff --git a/drivers/video/tegra/host/vi/vi.c b/drivers/video/tegra/host/vi/vi.c
index a6f902a..3cfc7e3 100644
--- a/drivers/video/tegra/host/vi/vi.c
+++ b/drivers/video/tegra/host/vi/vi.c
@@ -25,7 +25,8 @@
#include "dev.h"
#include "bus_client.h"
-static int __devinit vi_probe(struct nvhost_device *dev)
+static int __devinit vi_probe(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
{
int err = 0;
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index b4b6241..a0c4156 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -32,7 +32,7 @@
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_mru.h"
diff --git a/drivers/video/tegra/nvmap/nvmap.h b/drivers/video/tegra/nvmap/nvmap.h
index 44a0d86..b0fb70f 100644
--- a/drivers/video/tegra/nvmap/nvmap.h
+++ b/drivers/video/tegra/nvmap/nvmap.h
@@ -30,7 +30,7 @@
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/atomic.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap_heap.h"
struct nvmap_device;
@@ -86,7 +86,7 @@ struct nvmap_handle {
struct mutex lock;
};
-#define NVMAP_DEFAULT_PAGE_POOL_SIZE 8192
+#ifdef CONFIG_NVMAP_PAGE_POOLS
#define NVMAP_UC_POOL NVMAP_HANDLE_UNCACHEABLE
#define NVMAP_WC_POOL NVMAP_HANDLE_WRITE_COMBINE
#define NVMAP_IWB_POOL NVMAP_HANDLE_INNER_CACHEABLE
@@ -103,11 +103,13 @@ struct nvmap_page_pool {
};
int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags);
+#endif
struct nvmap_share {
struct tegra_iovmm_client *iovmm;
wait_queue_head_t pin_wait;
struct mutex pin_lock;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
union {
struct nvmap_page_pool pools[NVMAP_NUM_POOLS];
struct {
@@ -117,6 +119,7 @@ struct nvmap_share {
struct nvmap_page_pool wb_pool;
};
};
+#endif
#ifdef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
struct mutex mru_lock;
struct list_head *mru_lists;
@@ -201,9 +204,6 @@ struct nvmap_handle *nvmap_get_handle_id(struct nvmap_client *client,
struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
size_t size);
-struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
- unsigned long id);
-
int nvmap_alloc_handle_id(struct nvmap_client *client,
unsigned long id, unsigned int heap_mask,
size_t align, unsigned int flags);
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index f84f38c..c78818711 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -39,7 +39,7 @@
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_ioctl.h"
@@ -1182,8 +1182,10 @@ static int nvmap_probe(struct platform_device *pdev)
init_waitqueue_head(&dev->iovmm_master.pin_wait);
mutex_init(&dev->iovmm_master.pin_lock);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
for (i = 0; i < NVMAP_NUM_POOLS; i++)
nvmap_page_pool_init(&dev->iovmm_master.pools[i], i);
+#endif
dev->iovmm_master.iovmm =
tegra_iovmm_alloc_client(dev_name(&pdev->dev), NULL,
@@ -1311,6 +1313,7 @@ static int nvmap_probe(struct platform_device *pdev)
dev, &debug_iovmm_clients_fops);
debugfs_create_file("allocations", 0664, iovmm_root,
dev, &debug_iovmm_allocations_fops);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
for (i = 0; i < NVMAP_NUM_POOLS; i++) {
char name[40];
char *memtype_string[] = {"uc", "wc",
@@ -1321,6 +1324,7 @@ static int nvmap_probe(struct platform_device *pdev)
iovmm_root,
&dev->iovmm_master.pools[i].npages);
}
+#endif
}
}
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 539b7ce..2f24ba5 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -36,7 +36,7 @@
#include <asm/pgtable.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include <linux/vmstat.h>
#include <linux/swap.h>
@@ -66,6 +66,9 @@
* preserve kmalloc space, if the array of pages exceeds PAGELIST_VMALLOC_MIN,
* the array is allocated using vmalloc. */
#define PAGELIST_VMALLOC_MIN (PAGE_SIZE * 2)
+
+#ifdef CONFIG_NVMAP_PAGE_POOLS
+
#define NVMAP_TEST_PAGE_POOL_SHRINKER 1
static bool enable_pp = 1;
static int pool_size[NVMAP_NUM_POOLS];
@@ -377,6 +380,7 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
int i;
static int reg = 1;
struct sysinfo info;
+ int highmem_pages = 0;
typedef int (*set_pages_array) (struct page **pages, int addrinarray);
set_pages_array s_cpa[] = {
set_pages_array_uc,
@@ -395,14 +399,16 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
return 0;
si_meminfo(&info);
- if (!pool_size[flags]) {
+ if (!pool_size[flags] && !CONFIG_NVMAP_PAGE_POOL_SIZE)
/* Use 3/8th of total ram for page pools.
* 1/8th for uc, 1/8th for wc and 1/8th for iwb.
*/
pool->max_pages = info.totalram >> 3;
- }
+ else
+ pool->max_pages = CONFIG_NVMAP_PAGE_POOL_SIZE;
+
if (pool->max_pages <= 0 || pool->max_pages >= info.totalram)
- pool->max_pages = NVMAP_DEFAULT_PAGE_POOL_SIZE;
+ goto fail;
pool_size[flags] = pool->max_pages;
pr_info("nvmap %s page pool size=%d pages",
s_memtype_str[flags], pool->max_pages);
@@ -425,7 +431,14 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
__free_page(page);
goto do_cpa;
}
+ if (PageHighMem(page))
+ highmem_pages++;
}
+ si_meminfo(&info);
+ pr_info("nvmap pool = %s, highmem=%d, pool_size=%d,"
+ "totalram=%lu, freeram=%lu, totalhigh=%lu, freehigh=%lu",
+ s_memtype_str[flags], highmem_pages, pool->max_pages,
+ info.totalram, info.freeram, info.totalhigh, info.freehigh);
do_cpa:
(*s_cpa[flags])(pool->page_array, pool->npages);
nvmap_page_pool_unlock(pool);
@@ -436,6 +449,7 @@ fail:
vfree(pool->page_array);
return -ENOMEM;
}
+#endif
static inline void *altalloc(size_t len)
{
@@ -460,7 +474,9 @@ void _nvmap_handle_free(struct nvmap_handle *h)
{
struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
unsigned int i, nr_page, page_index = 0;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
struct nvmap_page_pool *pool = NULL;
+#endif
if (nvmap_handle_remove(h->dev, h) != 0)
return;
@@ -481,6 +497,7 @@ void _nvmap_handle_free(struct nvmap_handle *h)
nvmap_mru_remove(share, h);
+#ifdef CONFIG_NVMAP_PAGE_POOLS
if (h->flags < NVMAP_NUM_POOLS)
pool = &share->pools[h->flags];
@@ -490,6 +507,7 @@ void _nvmap_handle_free(struct nvmap_handle *h)
break;
page_index++;
}
+#endif
if (page_index == nr_page)
goto skip_attr_restore;
@@ -538,12 +556,14 @@ static int handle_page_alloc(struct nvmap_client *client,
struct nvmap_handle *h, bool contiguous)
{
size_t size = PAGE_ALIGN(h->size);
- struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
unsigned int nr_page = size >> PAGE_SHIFT;
pgprot_t prot;
unsigned int i = 0, page_index = 0;
struct page **pages;
+#ifdef CONFIG_NVMAP_PAGE_POOLS
struct nvmap_page_pool *pool = NULL;
+ struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
+#endif
pages = altalloc(nr_page * sizeof(*pages));
if (!pages)
@@ -562,6 +582,7 @@ static int handle_page_alloc(struct nvmap_client *client,
pages[i] = nth_page(page, i);
} else {
+#ifdef CONFIG_NVMAP_PAGE_POOLS
if (h->flags < NVMAP_NUM_POOLS)
pool = &share->pools[h->flags];
@@ -572,7 +593,7 @@ static int handle_page_alloc(struct nvmap_client *client,
break;
page_index++;
}
-
+#endif
for (; i < nr_page; i++) {
pages[i] = nvmap_alloc_pages_exact(GFP_NVMAP,
PAGE_SIZE);
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.c b/drivers/video/tegra/nvmap/nvmap_heap.c
index 7474f31..a6fe78c 100644
--- a/drivers/video/tegra/nvmap/nvmap_heap.c
+++ b/drivers/video/tegra/nvmap/nvmap_heap.c
@@ -28,7 +28,7 @@
#include <linux/slab.h>
#include <linux/err.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap.h"
#include "nvmap_heap.h"
#include "nvmap_common.h"
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c
index 58bc71d..1478715 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.c
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c
@@ -31,7 +31,7 @@
#include <asm/tlbflush.h>
#include <mach/iovmm.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#include "nvmap_ioctl.h"
#include "nvmap.h"
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.h b/drivers/video/tegra/nvmap/nvmap_ioctl.h
index 5462768..300ce9b9 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.h
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.h
@@ -27,7 +27,7 @@
#ifdef __KERNEL__
#include <linux/file.h>
-#include <mach/nvmap.h>
+#include <linux/nvmap.h>
#endif
enum {