summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/tegra/dc/dc_priv.h1
-rw-r--r--drivers/video/tegra/host/Makefile3
-rw-r--r--drivers/video/tegra/host/chip_support.h149
-rw-r--r--drivers/video/tegra/host/debug.c295
-rw-r--r--drivers/video/tegra/host/debug.h43
-rw-r--r--drivers/video/tegra/host/dev.c165
-rw-r--r--drivers/video/tegra/host/dev.h12
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c4
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c285
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.h19
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c306
-rw-r--r--drivers/video/tegra/host/nvhost_channel.h5
-rw-r--r--drivers/video/tegra/host/nvhost_cpuaccess.c23
-rw-r--r--drivers/video/tegra/host/nvhost_cpuaccess.h17
-rw-r--r--drivers/video/tegra/host/nvhost_hwctx.h14
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c219
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h10
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c194
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.h72
-rw-r--r--drivers/video/tegra/host/t20/3dctx_t20.c (renamed from drivers/video/tegra/host/nvhost_3dctx.c)18
-rw-r--r--drivers/video/tegra/host/t20/Makefile11
-rw-r--r--drivers/video/tegra/host/t20/cdma_t20.c243
-rw-r--r--drivers/video/tegra/host/t20/channel_t20.c367
-rw-r--r--drivers/video/tegra/host/t20/cpuaccess_t20.c55
-rw-r--r--drivers/video/tegra/host/t20/debug_t20.c308
-rw-r--r--drivers/video/tegra/host/t20/hardware_t20.h (renamed from drivers/video/tegra/host/nvhost_hardware.h)20
-rw-r--r--drivers/video/tegra/host/t20/intr_t20.c201
-rw-r--r--drivers/video/tegra/host/t20/syncpt_t20.c214
-rw-r--r--drivers/video/tegra/host/t20/syncpt_t20.h68
-rw-r--r--drivers/video/tegra/host/t20/t20.c51
-rw-r--r--drivers/video/tegra/host/t20/t20.h32
-rw-r--r--drivers/video/tegra/host/t30/Makefile4
-rw-r--r--drivers/video/tegra/host/t30/t30.c54
33 files changed, 2196 insertions, 1286 deletions
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 31706dee5c47..df03d171203e 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -25,6 +25,7 @@
#include <linux/completion.h>
#include "../host/dev.h"
+#include "../host/t20/syncpt_t20.h"
#define WIN_IS_TILED(win) ((win)->flags & TEGRA_WIN_FLAG_TILED)
#define WIN_IS_ENABLED(win) ((win)->flags & TEGRA_WIN_FLAG_ENABLED)
diff --git a/drivers/video/tegra/host/Makefile b/drivers/video/tegra/host/Makefile
index c13f8348ed9c..e6b7edfa917f 100644
--- a/drivers/video/tegra/host/Makefile
+++ b/drivers/video/tegra/host/Makefile
@@ -5,9 +5,10 @@ nvhost-objs = \
nvhost_cpuaccess.o \
nvhost_intr.o \
nvhost_channel.o \
- nvhost_3dctx.o \
dev.o \
bus.o \
debug.o
+obj-$(CONFIG_TEGRA_GRHOST) += t20/
+obj-$(CONFIG_TEGRA_GRHOST) += t30/
obj-$(CONFIG_TEGRA_GRHOST) += nvhost.o
diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h
new file mode 100644
index 000000000000..0f44770b6263
--- /dev/null
+++ b/drivers/video/tegra/host/chip_support.h
@@ -0,0 +1,149 @@
+/*
+ * drivers/video/tegra/host/chip_support.h
+ *
+ * Tegra Graphics Host Chip Support
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _NVHOST_CHIP_SUPPORT_H_
+#define _NVHOST_CHIP_SUPPORT_H_
+
+struct output;
+
+struct nvhost_chip_support {
+ struct {
+ int (*init)(struct nvhost_channel *,
+ struct nvhost_master *,
+ int chid);
+ int (*submit)(struct nvhost_channel *,
+ struct nvhost_hwctx *,
+ struct nvmap_client *,
+ u32 *gather,
+ u32 *gather_end,
+ struct nvhost_waitchk *waitchk,
+ struct nvhost_waitchk *waitchk_end,
+ u32 waitchk_mask,
+ struct nvmap_handle **unpins,
+ int nr_unpins,
+ u32 syncpt_id,
+ u32 syncpt_incrs,
+ u32 *syncpt_value,
+ bool null_kickoff);
+ } channel;
+
+ struct {
+ void (*start)(struct nvhost_cdma *);
+ void (*stop)(struct nvhost_cdma *);
+ void (*kick)(struct nvhost_cdma *);
+ } cdma;
+
+ struct {
+ void (*reset)(struct push_buffer *);
+ int (*init)(struct push_buffer *);
+ void (*destroy)(struct push_buffer *);
+ void (*push_to)(struct push_buffer *,
+ u32 op1, u32 op2);
+ void (*pop_from)(struct push_buffer *,
+ unsigned int slots);
+ u32 (*space)(struct push_buffer *);
+ u32 (*putptr)(struct push_buffer *);
+ } push_buffer;
+
+ struct {
+ void (*show_channel_cdma)(struct nvhost_master *,
+ struct output *,
+ int chid);
+ void (*show_channel_fifo)(struct nvhost_master *,
+ struct output *,
+ int chid);
+ void (*show_mlocks)(struct nvhost_master *m,
+ struct output *o);
+
+ } debug;
+
+ struct {
+ void (*reset)(struct nvhost_syncpt *, u32 id);
+ void (*reset_wait_base)(struct nvhost_syncpt *, u32 id);
+ void (*read_wait_base)(struct nvhost_syncpt *, u32 id);
+ u32 (*update_min)(struct nvhost_syncpt *, u32 id);
+ void (*cpu_incr)(struct nvhost_syncpt *, u32 id);
+ int (*wait_check)(struct nvhost_syncpt *sp,
+ struct nvmap_client *nvmap,
+ u32 waitchk_mask,
+ struct nvhost_waitchk *wait,
+ struct nvhost_waitchk *waitend);
+ void (*debug)(struct nvhost_syncpt *);
+ const char * (*name)(struct nvhost_syncpt *, u32 id);
+ } syncpt;
+
+ struct {
+ void (*init_host_sync)(struct nvhost_intr *);
+ void (*set_host_clocks_per_usec)(
+ struct nvhost_intr *, u32 clocks);
+ void (*set_syncpt_threshold)(
+ struct nvhost_intr *, u32 id, u32 thresh);
+ void (*enable_syncpt_intr)(struct nvhost_intr *, u32 id);
+ void (*disable_all_syncpt_intrs)(struct nvhost_intr *);
+ int (*request_host_general_irq)(struct nvhost_intr *);
+ void (*free_host_general_irq)(struct nvhost_intr *);
+ } intr;
+
+ struct {
+ int (*mutex_try_lock)(struct nvhost_cpuaccess *,
+ unsigned int idx);
+ void (*mutex_unlock)(struct nvhost_cpuaccess *,
+ unsigned int idx);
+ } cpuaccess;
+};
+
+
+int nvhost_init_t20_support(struct nvhost_master *host);
+int nvhost_init_t30_support(struct nvhost_master *host);
+
+
+/* place holder for chip id assumed to live in kernel/arch/arm/mach-tegra */
+struct tegra_chip_info {
+#define TEGRA_SOC_CHIP_ARCH_T20 0
+#define TEGRA_SOC_CHIP_IMPL_T20 0
+ u16 arch;
+#define TEGRA_SOC_CHIP_ARCH_T30 1
+#define TEGRA_SOC_CHIP_IMPL_T30 0
+ u16 impl;
+};
+
+#if 0
+extern int tegra_get_chip_info(struct tegra_chip_info *);
+#else
+static inline int tegra_get_chip_info(struct tegra_chip_info *ci)
+{
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ ci->arch = TEGRA_SOC_CHIP_ARCH_T30;
+ ci->impl = TEGRA_SOC_CHIP_IMPL_T30;
+
+#elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ ci->arch = TEGRA_SOC_CHIP_ARCH_T20;
+ ci->impl = TEGRA_SOC_CHIP_IMPL_T20;
+
+#else
+ return -ENODEV;
+#endif
+
+ return 0;
+}
+#endif
+
+#endif /* _NVHOST_CHIP_SUPPORT_H_ */
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index f4c6562a9b43..c0cdf65ccd18 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -23,26 +23,11 @@
#include <asm/io.h>
#include "dev.h"
-
-struct output {
- void (*fn)(void *ctx, const char* str, size_t len);
- void *ctx;
- char buf[256];
-};
+#include "debug.h"
pid_t nvhost_debug_null_kickoff_pid;
-static void write_to_seqfile(void *ctx, const char* str, size_t len)
-{
- seq_write((struct seq_file *)ctx, str, len);
-}
-
-static void write_to_printk(void *ctx, const char* str, size_t len)
-{
- printk("%s", str);
-}
-
-static void output(struct output *o, const char* fmt, ...)
+void nvhost_debug_output(struct output *o, const char* fmt, ...)
{
va_list args;
int len;
@@ -53,294 +38,40 @@ static void output(struct output *o, const char* fmt, ...)
o->fn(o->ctx, o->buf, len);
}
-enum {
- NVHOST_DBG_STATE_CMD = 0,
- NVHOST_DBG_STATE_DATA = 1,
- NVHOST_DBG_STATE_GATHER = 2
-};
-
-static int show_channel_command(struct output *o, u32 val, int *count)
-{
- unsigned mask;
- unsigned subop;
-
- switch (val >> 28) {
- case 0x0:
- mask = val & 0x3f;
- if (mask) {
- output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
- val >> 6 & 0x3ff, val >> 16 & 0xfff, mask);
- *count = hweight8(mask);
- return NVHOST_DBG_STATE_DATA;
- } else {
- output(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff);
- return NVHOST_DBG_STATE_CMD;
- }
-
- case 0x1:
- output(o, "INCR(offset=%03x, [", val >> 16 & 0xfff);
- *count = val & 0xffff;
- return NVHOST_DBG_STATE_DATA;
-
- case 0x2:
- output(o, "NONINCR(offset=%03x, [", val >> 16 & 0xfff);
- *count = val & 0xffff;
- return NVHOST_DBG_STATE_DATA;
-
- case 0x3:
- mask = val & 0xffff;
- output(o, "MASK(offset=%03x, mask=%03x, [",
- val >> 16 & 0xfff, mask);
- *count = hweight16(mask);
- return NVHOST_DBG_STATE_DATA;
-
- case 0x4:
- output(o, "IMM(offset=%03x, data=%03x)\n",
- val >> 16 & 0xfff, val & 0xffff);
- return NVHOST_DBG_STATE_CMD;
-
- case 0x5:
- output(o, "RESTART(offset=%08x)\n", val << 4);
- return NVHOST_DBG_STATE_CMD;
-
- case 0x6:
- output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
- val >> 16 & 0xfff, val >> 15 & 0x1, val >> 14 & 0x1,
- val & 0x3fff);
- *count = val & 0x3fff; // TODO: insert
- return NVHOST_DBG_STATE_GATHER;
-
- case 0xe:
- subop = val >> 24 & 0xf;
- if (subop == 0)
- output(o, "ACQUIRE_MLOCK(index=%d)\n", val & 0xff);
- else if (subop == 1)
- output(o, "RELEASE_MLOCK(index=%d)\n", val & 0xff);
- else
- output(o, "EXTEND_UNKNOWN(%08x)\n", val);
- return NVHOST_DBG_STATE_CMD;
-
- default:
- return NVHOST_DBG_STATE_CMD;
- }
-}
-
-static void show_channel_gather(struct output *o, phys_addr_t phys_addr,
- u32 words);
-
-static void show_channel_word(struct output *o, int *state, int *count,
- u32 addr, u32 val)
-{
- switch (*state) {
- case NVHOST_DBG_STATE_CMD:
- if (addr)
- output(o, "%08x: %08x:", addr, val);
- else
- output(o, "%08x:", val);
-
- *state = show_channel_command(o, val, count);
- if (*state == NVHOST_DBG_STATE_DATA && *count == 0) {
- *state = NVHOST_DBG_STATE_CMD;
- output(o, "])\n");
- }
- break;
-
- case NVHOST_DBG_STATE_DATA:
- (*count)--;
- output(o, "%08x%s", val, *count > 0 ? ", " : "])\n");
- if (*count == 0)
- *state = NVHOST_DBG_STATE_CMD;
- break;
-
- case NVHOST_DBG_STATE_GATHER:
- *state = NVHOST_DBG_STATE_CMD;
- output(o, "%08x]):\n", val);
- show_channel_gather(o, val, *count);
- break;
- }
-}
-
-/*
- * TODO: This uses ioremap_xxx on memory which is deprecated.
- * Also, it won't work properly with SMMU.
- */
-static void show_channel_gather(struct output *o, phys_addr_t phys_addr,
- u32 words)
-{
- phys_addr_t map_base = phys_addr & PAGE_MASK;
- phys_addr_t map_end = (phys_addr + words * 4 + PAGE_SIZE - 1) & PAGE_MASK;
- phys_addr_t map_size = map_end - map_base;
- phys_addr_t map_offset = phys_addr - map_base;
- void *map_addr = ioremap_nocache(map_base, map_size);
- int state = NVHOST_DBG_STATE_CMD;
- int count, i;
-
- if (!map_addr)
- return;
- for (i = 0; i < words; i++)
- show_channel_word(o, &state, &count, phys_addr + i * 4,
- readl(map_addr + map_offset + i * 4));
- iounmap(map_addr);
-}
-
-static void show_channel_pair(struct output *o, u32 addr,
- u32 w0, u32 w1)
-{
- int state = NVHOST_DBG_STATE_CMD;
- int count;
-
- show_channel_word(o, &state, &count, addr, w0);
- show_channel_word(o, &state, &count, addr, w1);
-}
-
-static void show_channel_cdma(struct nvhost_master *m,
- struct output *o, int chid)
-{
- struct nvhost_channel *channel = m->channels + chid;
- u32 dmaput, dmaget, dmactrl;
- u32 cbstat, cbread;
- u32 val, base, baseval;
- u32 pbw[2];
-
- dmaput = readl(channel->aperture + HOST1X_CHANNEL_DMAPUT);
- dmaget = readl(channel->aperture + HOST1X_CHANNEL_DMAGET);
- dmactrl = readl(channel->aperture + HOST1X_CHANNEL_DMACTRL);
- cbread = readl(m->aperture + HOST1X_SYNC_CBREAD(chid));
- cbstat = readl(m->aperture + HOST1X_SYNC_CBSTAT(chid));
-
- output(o, "%d-%s (%d): ", chid,
- channel->mod.name, atomic_read(&channel->mod.refcount));
-
- if ((dmactrl & 1) || !channel->cdma.push_buffer.mapped) {
- output(o, "inactive\n\n");
- return;
- }
-
- switch (cbstat) {
- case 0x00010008:
- output(o, "waiting on syncpt %d val %d\n",
- cbread >> 24, cbread & 0xffffff);
- break;
-
- case 0x00010009:
- base = (cbread >> 16) & 0xff;
- val = readl(m->aperture + HOST1X_SYNC_SYNCPT_BASE(base));
- baseval = val & 0xffff;
- val = cbread & 0xffff;
- output(o, "waiting on syncpt %d val %d "
- "(base %d = %d; offset = %d)\n",
- cbread >> 24, baseval + val,
- base, baseval, val);
- break;
-
- default:
- output(o, "active class %02x, offset %04x, val %08x\n",
- cbstat >> 16, cbstat & 0xffff, cbread);
- break;
- }
-
- nvhost_cdma_peek(&channel->cdma, dmaget, -1, pbw);
- show_channel_pair(o, chid, pbw[0], pbw[1]);
- output(o, "\n");
-}
-
-void show_channel_fifo(struct nvhost_master *m,
- struct output *o, int chid)
-{
- u32 val, rd_ptr, wr_ptr, start, end;
- int state, count;
-
- val = readl(m->aperture + HOST1X_CHANNEL_FIFOSTAT);
- if (val & (1 << 10))
- return;
-
- writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- writel((1 << 31) | (chid << 16),
- m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
-
- val = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS);
- rd_ptr = val & 0x1ff;
- wr_ptr = (val >> 16) & 0x1ff;
-
- val = readl(m->aperture + HOST1X_SYNC_CF_SETUP(chid));
- start = val & 0x1ff;
- end = (val >> 16) & 0x1ff;
-
- state = NVHOST_DBG_STATE_CMD;
- output(o, "%d: fifo:\n", chid);
-
- do {
- writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- writel((1 << 31) | (chid << 16) | rd_ptr,
- m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
- val = readl(m->aperture + HOST1X_SYNC_CFPEEK_READ);
-
- show_channel_word(o, &state, &count, 0, val);
-
- if (rd_ptr == end)
- rd_ptr = start;
- else
- rd_ptr++;
- } while (rd_ptr != wr_ptr);
-
- if (state == NVHOST_DBG_STATE_DATA)
- output(o, ", ...])\n");
- output(o, "\n");
-
- writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
-}
static void show_channels(struct nvhost_master *m, struct output *o)
{
int i;
- output(o, "---- channels ----\n");
- for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
- show_channel_cdma(m, o, i);
- show_channel_fifo(m, o, i);
+ nvhost_debug_output(o, "---- channels ----\n");
+ for (i = 0; i < m->nb_channels; i++) {
+ m->op.debug.show_channel_cdma(m, o, i);
+ m->op.debug.show_channel_fifo(m, o, i);
}
}
-static void show_mlocks(struct nvhost_master *m, struct output *o)
-{
- u32 __iomem *mlo_regs = m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0;
- int i;
-
- output(o, "---- mlocks ----\n");
- for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
- u32 owner = readl(mlo_regs + i);
- if (owner & 0x1)
- output(o, "%d: locked by channel %d\n",
- i, (owner >> 8) & 0xf);
- else if (owner & 0x2)
- output(o, "%d: locked by cpu\n", i);
- else
- output(o, "%d: unlocked\n", i);
- }
- output(o, "\n");
-}
static void show_syncpts(struct nvhost_master *m, struct output *o)
{
int i;
-
- output(o, "---- syncpts ----\n");
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
+ BUG_ON(!m->op.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);
if (!max)
continue;
- output(o, "id %d (%s) min %d max %d\n",
- i, nvhost_syncpt_name(i),
+ nvhost_debug_output(o, "id %d (%s) min %d max %d\n",
+ i, m->op.syncpt.name(&m->syncpt, i),
nvhost_syncpt_update_min(&m->syncpt, i), max);
}
- output(o, "\n");
+ nvhost_debug_output(o, "\n");
}
static void show_all(struct nvhost_master *m, struct output *o)
{
nvhost_module_busy(&m->mod);
- show_mlocks(m, o);
+ m->op.debug.show_mlocks(m, o);
show_syncpts(m, o);
show_channels(m, o);
diff --git a/drivers/video/tegra/host/debug.h b/drivers/video/tegra/host/debug.h
new file mode 100644
index 000000000000..829c29ecda2a
--- /dev/null
+++ b/drivers/video/tegra/host/debug.h
@@ -0,0 +1,43 @@
+/*
+ * drivers/video/tegra/host/debug.h
+ *
+ * Tegra Graphics Host Debug
+ *
+ * Copyright (c) 2011 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef __NVHOST_DEBUG_H
+#define __NVHOST_DEBUG_H
+
+struct output {
+ void (*fn)(void *ctx, const char* str, size_t len);
+ void *ctx;
+ char buf[256];
+};
+
+static inline void write_to_seqfile(void *ctx, const char* str, size_t len)
+{
+ seq_write((struct seq_file *)ctx, str, len);
+}
+
+static inline void write_to_printk(void *ctx, const char* str, size_t len)
+{
+ printk("%s", str);
+}
+
+void nvhost_debug_output(struct output *o, const char* fmt, ...);
+
+#endif /*__NVHOST_DEBUG_H */
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
index 09ab33ff94d2..bfb7e111221b 100644
--- a/drivers/video/tegra/host/dev.c
+++ b/drivers/video/tegra/host/dev.c
@@ -45,7 +45,7 @@
#define IFACE_NAME "nvhost"
static int nvhost_major = NVHOST_MAJOR;
-static int nvhost_minor = NVHOST_CHANNEL_BASE;
+static int nvhost_minor;
static unsigned int register_sets;
struct nvhost_channel_userctx {
@@ -65,7 +65,7 @@ struct nvhost_channel_userctx {
struct nvhost_ctrl_userctx {
struct nvhost_master *dev;
- u32 mod_locks[NV_HOST1X_NB_MLOCKS];
+ u32 *mod_locks;
};
static int nvhost_channelrelease(struct inode *inode, struct file *filp)
@@ -308,7 +308,8 @@ static int nvhost_ioctl_channel_flush(
null_kickoff = 1;
/* context switch if needed, and submit user's gathers to the channel */
- err = nvhost_channel_submit(ctx->ch, ctx->hwctx, ctx->nvmap,
+ BUG_ON(!channel_op(ctx->ch).submit);
+ err = channel_op(ctx->ch).submit(ctx->ch, ctx->hwctx, ctx->nvmap,
ctx->gathers, ctx->cur_gather,
ctx->waitchks, ctx->cur_waitchk,
ctx->hdr.waitchk_mask,
@@ -438,9 +439,10 @@ static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
filp->private_data = NULL;
if (priv->mod_locks[0])
nvhost_module_idle(&priv->dev->mod);
- for (i = 1; i < NV_HOST1X_NB_MLOCKS; i++)
+ for (i = 1; i < priv->dev->nb_mlocks; i++)
if (priv->mod_locks[i])
nvhost_mutex_unlock(&priv->dev->cpuaccess, i);
+ kfree(priv->mod_locks);
kfree(priv);
return 0;
}
@@ -449,14 +451,21 @@ 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_ctrl_userctx *priv;
+ u32 *mod_locks;
trace_nvhost_ctrlopen(host->mod.name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
+ mod_locks = kzalloc(sizeof(u32)*host->nb_mlocks, GFP_KERNEL);
+
+ if (!(priv && mod_locks)) {
+ kfree(priv);
+ kfree(mod_locks);
return -ENOMEM;
+ }
priv->dev = host;
+ priv->mod_locks = mod_locks;
filp->private_data = priv;
return 0;
}
@@ -465,7 +474,7 @@ static int nvhost_ioctl_ctrl_syncpt_read(
struct nvhost_ctrl_userctx *ctx,
struct nvhost_ctrl_syncpt_read_args *args)
{
- if (args->id >= NV_HOST1X_SYNCPT_NB_PTS)
+ if (args->id >= ctx->dev->syncpt.nb_pts)
return -EINVAL;
trace_nvhost_ioctl_ctrl_syncpt_read(args->id);
args->value = nvhost_syncpt_read(&ctx->dev->syncpt, args->id);
@@ -476,7 +485,7 @@ static int nvhost_ioctl_ctrl_syncpt_incr(
struct nvhost_ctrl_userctx *ctx,
struct nvhost_ctrl_syncpt_incr_args *args)
{
- if (args->id >= NV_HOST1X_SYNCPT_NB_PTS)
+ if (args->id >= ctx->dev->syncpt.nb_pts)
return -EINVAL;
trace_nvhost_ioctl_ctrl_syncpt_incr(args->id);
nvhost_syncpt_incr(&ctx->dev->syncpt, args->id);
@@ -488,7 +497,7 @@ static int nvhost_ioctl_ctrl_syncpt_waitex(
struct nvhost_ctrl_syncpt_waitex_args *args)
{
u32 timeout;
- if (args->id >= NV_HOST1X_SYNCPT_NB_PTS)
+ if (args->id >= ctx->dev->syncpt.nb_pts)
return -EINVAL;
if (args->timeout == NVHOST_NO_TIMEOUT)
timeout = MAX_SCHEDULE_TIMEOUT;
@@ -506,7 +515,7 @@ static int nvhost_ioctl_ctrl_module_mutex(
struct nvhost_ctrl_module_mutex_args *args)
{
int err = 0;
- if (args->id >= NV_HOST1X_NB_MLOCKS ||
+ if (args->id >= ctx->dev->nb_mlocks ||
args->lock > 1)
return -EINVAL;
@@ -538,7 +547,7 @@ static int nvhost_ioctl_ctrl_module_regrdwr(
void *values = args->values;
u32 vals[64];
- if (!nvhost_access_module_regs(&ctx->dev->cpuaccess, args->id) ||
+ if (!(args->id < ctx->dev->nb_modules) ||
(num_offsets == 0))
return -EINVAL;
@@ -638,7 +647,7 @@ static void power_host(struct nvhost_module *mod, enum nvhost_power_action actio
*/
} else if (action == NVHOST_POWER_ACTION_OFF) {
int i;
- for (i = 0; i < NVHOST_NUMCHANNELS; i++)
+ for (i = 0; i < dev->nb_channels; i++)
nvhost_channel_suspend(&dev->channels[i]);
nvhost_syncpt_save(&dev->syncpt);
nvhost_intr_stop(&dev->intr);
@@ -658,10 +667,11 @@ static int __devinit nvhost_user_init(struct nvhost_master *host)
if (nvhost_major) {
devno = MKDEV(nvhost_major, nvhost_minor);
- err = register_chrdev_region(devno, NVHOST_NUMCHANNELS + 1, IFACE_NAME);
+ err = register_chrdev_region(devno, host->nb_channels + 1,
+ IFACE_NAME);
} else {
err = alloc_chrdev_region(&devno, nvhost_minor,
- NVHOST_NUMCHANNELS + 1, IFACE_NAME);
+ host->nb_channels + 1, IFACE_NAME);
nvhost_major = MAJOR(devno);
}
if (err < 0) {
@@ -669,14 +679,9 @@ static int __devinit nvhost_user_init(struct nvhost_master *host)
goto fail;
}
- for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
+ for (i = 0; i < host->nb_channels; i++) {
struct nvhost_channel *ch = &host->channels[i];
- if (!strcmp(ch->desc->name, "display") &&
- !nvhost_access_module_regs(&host->cpuaccess,
- NVHOST_MODULE_DISPLAY_A))
- continue;
-
cdev_init(&ch->cdev, &nvhost_channelops);
ch->cdev.owner = THIS_MODULE;
@@ -697,7 +702,7 @@ 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 + NVHOST_NUMCHANNELS);
+ devno = MKDEV(nvhost_major, nvhost_minor + host->nb_channels);
err = cdev_add(&host->cdev, devno, 1);
if (err < 0)
goto fail;
@@ -714,6 +719,91 @@ fail:
return err;
}
+static void nvhost_remove_chip_support(struct nvhost_master *host)
+{
+
+ kfree(host->channels);
+ host->channels = 0;
+
+ kfree(host->syncpt.min_val);
+ host->syncpt.min_val = 0;
+
+ kfree(host->syncpt.max_val);
+ host->syncpt.max_val = 0;
+
+ kfree(host->syncpt.base_val);
+ host->syncpt.base_val = 0;
+
+ kfree(host->intr.syncpt);
+ host->intr.syncpt = 0;
+
+ kfree(host->cpuaccess.regs);
+ host->cpuaccess.regs = 0;
+
+ kfree(host->cpuaccess.reg_mem);
+ host->cpuaccess.reg_mem = 0;
+
+ kfree(host->cpuaccess.lock_counts);
+ host->cpuaccess.lock_counts = 0;
+}
+
+static int __devinit nvhost_init_chip_support(struct nvhost_master *host)
+{
+ int err;
+ err = tegra_get_chip_info(&host->chip_info);
+ if (err)
+ return err;
+
+ switch (host->chip_info.arch) {
+ case TEGRA_SOC_CHIP_ARCH_T20:
+ err = nvhost_init_t20_support(host);
+ break;
+
+ case TEGRA_SOC_CHIP_ARCH_T30:
+ err = nvhost_init_t30_support(host);
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ 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->syncpt.min_val = kzalloc(sizeof(atomic_t) *
+ host->syncpt.nb_pts, GFP_KERNEL);
+
+ host->syncpt.max_val = kzalloc(sizeof(atomic_t) *
+ host->syncpt.nb_pts, GFP_KERNEL);
+
+ host->syncpt.base_val = kzalloc(sizeof(u32) *
+ host->syncpt.nb_bases, GFP_KERNEL);
+
+ host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
+ host->syncpt.nb_pts, GFP_KERNEL);
+
+ host->cpuaccess.reg_mem = kzalloc(sizeof(struct resource *) *
+ host->nb_modules, GFP_KERNEL);
+
+ host->cpuaccess.regs = kzalloc(sizeof(void __iomem *) *
+ host->nb_modules, GFP_KERNEL);
+
+ host->cpuaccess.lock_counts = kzalloc(sizeof(atomic_t) *
+ host->nb_mlocks, GFP_KERNEL);
+
+ if (!(host->channels && host->syncpt.min_val &&
+ host->syncpt.max_val && host->syncpt.base_val &&
+ host->intr.syncpt && host->cpuaccess.reg_mem &&
+ host->cpuaccess.regs && host->cpuaccess.lock_counts)) {
+ /* frees happen in the support removal phase */
+ return -ENOMEM;
+ }
+
+ return 0;
+}
static int __devinit nvhost_probe(struct platform_device *pdev)
{
struct nvhost_master *host;
@@ -755,27 +845,40 @@ static int __devinit nvhost_probe(struct platform_device *pdev)
err = -ENXIO;
goto fail;
}
- host->sync_aperture = host->aperture +
- (NV_HOST1X_CHANNEL0_BASE +
- HOST1X_CHANNEL_SYNC_REG_BASE);
- for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
+ err = nvhost_init_chip_support(host);
+ if (err) {
+ dev_err(&pdev->dev, "failed to init chip support\n");
+ goto fail;
+ }
+
+ for (i = 0; i < host->nb_channels; i++) {
struct nvhost_channel *ch = &host->channels[i];
- err = nvhost_channel_init(ch, host, i);
+ BUG_ON(!host_channel_op(host).init);
+ err = host_channel_op(host).init(ch, host, i);
if (err < 0) {
dev_err(&pdev->dev, "failed to init channel %d\n", i);
goto fail;
}
}
+
err = nvhost_cpuaccess_init(&host->cpuaccess, pdev);
- if (err) goto fail;
+ if (err)
+ goto fail;
+
err = nvhost_intr_init(&host->intr, intr1->start, intr0->start);
- if (err) goto fail;
+ if (err)
+ goto fail;
+
err = nvhost_user_init(host);
- if (err) goto fail;
+ if (err)
+ goto fail;
+
err = nvhost_module_init(&host->mod, "host1x", power_host, NULL, &pdev->dev);
- if (err) goto fail;
+ if (err)
+ goto fail;
+
platform_set_drvdata(pdev, host);
@@ -791,6 +894,7 @@ static int __devinit nvhost_probe(struct platform_device *pdev)
return 0;
fail:
+ nvhost_remove_chip_support(host);
if (host->nvmap)
nvmap_client_put(host->nvmap);
/* TODO: [ahatala 2010-05-04] */
@@ -800,6 +904,9 @@ fail:
static int __exit nvhost_remove(struct platform_device *pdev)
{
+ struct nvhost_master *host = platform_get_drvdata(pdev);
+ nvhost_remove_chip_support(host);
+ /*kfree(host);?*/
return 0;
}
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h
index 688fa431a616..ee79bddf05d5 100644
--- a/drivers/video/tegra/host/dev.h
+++ b/drivers/video/tegra/host/dev.h
@@ -28,7 +28,7 @@
#include "nvhost_intr.h"
#include "nvhost_cpuaccess.h"
#include "nvhost_channel.h"
-#include "nvhost_hardware.h"
+#include "chip_support.h"
#define NVHOST_MAJOR 0 /* dynamic */
@@ -43,9 +43,17 @@ struct nvhost_master {
struct nvhost_syncpt syncpt;
struct nvmap_client *nvmap;
struct nvhost_cpuaccess cpuaccess;
+ u32 nb_mlocks;
struct nvhost_intr intr;
struct nvhost_module mod;
- struct nvhost_channel channels[NVHOST_NUMCHANNELS];
+ struct nvhost_channel *channels;
+ u32 nb_channels;
+ u32 nb_modules;
+
+ u32 sync_queue_size;
+
+ struct tegra_chip_info chip_info;
+ struct nvhost_chip_support op;
};
void nvhost_debug_init(struct nvhost_master *master);
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 8d06ee731dca..725aebfc0c9a 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -205,14 +205,14 @@ static void debug_not_idle(struct nvhost_master *dev)
int i;
bool lock_released = true;
- for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
+ for (i = 0; i < dev->nb_channels; i++) {
struct nvhost_module *m = &dev->channels[i].mod;
if (m->name)
printk("tegra_grhost: %s: refcnt %d\n",
m->name, atomic_read(&m->refcount));
}
- for (i = 0; i < NV_HOST1X_SYNC_MLOCK_NUM; i++) {
+ for (i = 0; i < dev->nb_mlocks; i++) {
int c = atomic_read(&dev->cpuaccess.lock_counts[i]);
if (c) {
printk("tegra_grhost: lock id %d: refcnt %d\n", i, c);
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
index 05d563c31c8f..edebeeb5ea7b 100644
--- a/drivers/video/tegra/host/nvhost_cdma.c
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -23,7 +23,7 @@
#include "nvhost_cdma.h"
#include "dev.h"
#include <asm/cacheflush.h>
-
+#include <linux/slab.h>
/*
* TODO:
* stats
@@ -32,132 +32,6 @@
* - some channels hardly need any, some channels (3d) could use more
*/
-#define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
-#define cdma_to_dev(cdma) ((cdma_to_channel(cdma))->dev)
-#define cdma_to_nvmap(cdma) ((cdma_to_dev(cdma))->nvmap)
-#define pb_to_cdma(pb) container_of(pb, struct nvhost_cdma, push_buffer)
-
-/*
- * push_buffer
- *
- * The push buffer is a circular array of words to be fetched by command DMA.
- * Note that it works slightly differently to the sync queue; fence == cur
- * means that the push buffer is full, not empty.
- */
-
-// 8 bytes per slot. (This number does not include the final RESTART.)
-#define PUSH_BUFFER_SIZE (NVHOST_GATHER_QUEUE_SIZE * 8)
-
-static void destroy_push_buffer(struct push_buffer *pb);
-
-/**
- * Reset to empty push buffer
- */
-static void reset_push_buffer(struct push_buffer *pb)
-{
- pb->fence = PUSH_BUFFER_SIZE - 8;
- pb->cur = 0;
-}
-
-/**
- * Init push buffer resources
- */
-static int init_push_buffer(struct push_buffer *pb)
-{
- struct nvhost_cdma *cdma = pb_to_cdma(pb);
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- pb->mem = NULL;
- pb->mapped = NULL;
- pb->phys = 0;
- reset_push_buffer(pb);
-
- /* allocate and map pushbuffer memory */
- pb->mem = nvmap_alloc(nvmap, PUSH_BUFFER_SIZE + 4, 32,
- NVMAP_HANDLE_WRITE_COMBINE);
- if (IS_ERR_OR_NULL(pb->mem)) {
- pb->mem = NULL;
- goto fail;
- }
- pb->mapped = nvmap_mmap(pb->mem);
- if (pb->mapped == NULL)
- goto fail;
-
- /* pin pushbuffer and get physical address */
- pb->phys = nvmap_pin(nvmap, pb->mem);
- if (pb->phys >= 0xfffff000) {
- pb->phys = 0;
- goto fail;
- }
-
- /* put the restart at the end of pushbuffer memory */
- *(pb->mapped + (PUSH_BUFFER_SIZE >> 2)) = nvhost_opcode_restart(pb->phys);
-
- return 0;
-
-fail:
- destroy_push_buffer(pb);
- return -ENOMEM;
-}
-
-/**
- * Clean up push buffer resources
- */
-static void destroy_push_buffer(struct push_buffer *pb)
-{
- struct nvhost_cdma *cdma = pb_to_cdma(pb);
- struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
- if (pb->mapped)
- nvmap_munmap(pb->mem, pb->mapped);
-
- if (pb->phys != 0)
- nvmap_unpin(nvmap, pb->mem);
-
- if (pb->mem)
- nvmap_free(nvmap, pb->mem);
-
- pb->mem = NULL;
- pb->mapped = NULL;
- pb->phys = 0;
-}
-
-/**
- * Push two words to the push buffer
- * Caller must ensure push buffer is not full
- */
-static void push_to_push_buffer(struct push_buffer *pb, u32 op1, u32 op2)
-{
- u32 cur = pb->cur;
- u32 *p = (u32*)((u32)pb->mapped + cur);
- BUG_ON(cur == pb->fence);
- *(p++) = op1;
- *(p++) = op2;
- pb->cur = (cur + 8) & (PUSH_BUFFER_SIZE - 1);
- /* printk("push_to_push_buffer: op1=%08x; op2=%08x; cur=%x\n", op1, op2, pb->cur); */
-}
-
-/**
- * Pop a number of two word slots from the push buffer
- * Caller must ensure push buffer is not empty
- */
-static void pop_from_push_buffer(struct push_buffer *pb, unsigned int slots)
-{
- pb->fence = (pb->fence + slots * 8) & (PUSH_BUFFER_SIZE - 1);
-}
-
-/**
- * Return the number of two word slots free in the push buffer
- */
-static u32 push_buffer_space(struct push_buffer *pb)
-{
- return ((pb->fence - pb->cur) & (PUSH_BUFFER_SIZE - 1)) / 8;
-}
-
-static u32 push_buffer_putptr(struct push_buffer *pb)
-{
- return pb->phys + pb->cur;
-}
-
-
/* Sync Queue
*
* The sync queue is a circular buffer of u32s interpreted as:
@@ -198,12 +72,18 @@ static void reset_sync_queue(struct sync_queue *queue)
*/
static unsigned int sync_queue_space(struct sync_queue *queue)
{
+ struct nvhost_cdma *cdma;
+ struct nvhost_master *host;
+
unsigned int read = queue->read;
unsigned int write = queue->write;
u32 size;
- BUG_ON(read > (NVHOST_SYNC_QUEUE_SIZE - SYNC_QUEUE_MIN_ENTRY));
- BUG_ON(write > (NVHOST_SYNC_QUEUE_SIZE - SYNC_QUEUE_MIN_ENTRY));
+ cdma = container_of(queue, struct nvhost_cdma, sync_queue);
+ host = cdma_to_dev(cdma);
+
+ BUG_ON(read > (host->sync_queue_size - SYNC_QUEUE_MIN_ENTRY));
+ BUG_ON(write > (host->sync_queue_size - SYNC_QUEUE_MIN_ENTRY));
/*
* We can use all of the space up to the end of the buffer, unless the
@@ -213,7 +93,7 @@ static unsigned int sync_queue_space(struct sync_queue *queue)
if (read > write) {
size = (read - 1) - write;
} else {
- size = NVHOST_SYNC_QUEUE_SIZE - write;
+ size = host->sync_queue_size - write;
/*
* If the read position is zero, it gets complicated. We can't
@@ -248,15 +128,20 @@ static void add_to_sync_queue(struct sync_queue *queue,
u32 nr_slots, struct nvmap_client *user_nvmap,
struct nvmap_handle **handles, u32 nr_handles)
{
+ struct nvhost_cdma *cdma;
+ struct nvhost_master *host;
u32 write = queue->write;
u32 *p = queue->buffer + write;
u32 size = 4 + (entry_size(nr_handles));
+ cdma = container_of(queue, struct nvhost_cdma, sync_queue);
+ host = cdma_to_dev(cdma);
+
BUG_ON(sync_point_id == NVSYNCPT_INVALID);
BUG_ON(sync_queue_space(queue) < nr_handles);
write += size;
- BUG_ON(write > NVHOST_SYNC_QUEUE_SIZE);
+ BUG_ON(write > host->sync_queue_size);
*p++ = sync_point_id;
*p++ = sync_point_value;
@@ -271,7 +156,7 @@ static void add_to_sync_queue(struct sync_queue *queue,
memcpy(p, handles, nr_handles * sizeof(struct nvmap_handle *));
/* If there's not enough room for another entry, wrap to the start. */
- if ((write + SYNC_QUEUE_MIN_ENTRY) > NVHOST_SYNC_QUEUE_SIZE) {
+ if ((write + SYNC_QUEUE_MIN_ENTRY) > host->sync_queue_size) {
/*
* It's an error for the read position to be zero, as that
* would mean we emptied the queue while adding something.
@@ -289,11 +174,15 @@ static void add_to_sync_queue(struct sync_queue *queue,
*/
static u32 *sync_queue_head(struct sync_queue *queue)
{
+ struct nvhost_cdma *cdma = container_of(queue,
+ struct nvhost_cdma,
+ sync_queue);
+ struct nvhost_master *host = cdma_to_dev(cdma);
u32 read = queue->read;
u32 write = queue->write;
- BUG_ON(read > (NVHOST_SYNC_QUEUE_SIZE - SYNC_QUEUE_MIN_ENTRY));
- BUG_ON(write > (NVHOST_SYNC_QUEUE_SIZE - SYNC_QUEUE_MIN_ENTRY));
+ BUG_ON(read > (host->sync_queue_size - SYNC_QUEUE_MIN_ENTRY));
+ BUG_ON(write > (host->sync_queue_size - SYNC_QUEUE_MIN_ENTRY));
if (read == write)
return NULL;
@@ -306,6 +195,10 @@ static u32 *sync_queue_head(struct sync_queue *queue)
static void
dequeue_sync_queue_head(struct sync_queue *queue)
{
+ struct nvhost_cdma *cdma = container_of(queue,
+ struct nvhost_cdma,
+ sync_queue);
+ struct nvhost_master *host = cdma_to_dev(cdma);
u32 read = queue->read;
u32 size;
@@ -314,62 +207,16 @@ dequeue_sync_queue_head(struct sync_queue *queue)
size = 4 + entry_size(queue->buffer[read + 3]);
read += size;
- BUG_ON(read > NVHOST_SYNC_QUEUE_SIZE);
+ BUG_ON(read > host->sync_queue_size);
/* If there's not enough room for another entry, wrap to the start. */
- if ((read + SYNC_QUEUE_MIN_ENTRY) > NVHOST_SYNC_QUEUE_SIZE)
+ if ((read + SYNC_QUEUE_MIN_ENTRY) > host->sync_queue_size)
read = 0;
queue->read = read;
}
-/*** Cdma internal stuff ***/
-
-/**
- * Start channel DMA
- */
-static void start_cdma(struct nvhost_cdma *cdma)
-{
- void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
-
- if (cdma->running)
- return;
-
- cdma->last_put = push_buffer_putptr(&cdma->push_buffer);
-
- writel(nvhost_channel_dmactrl(true, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
-
- /* set base, put, end pointer (all of memory) */
- writel(0, chan_regs + HOST1X_CHANNEL_DMASTART);
- writel(cdma->last_put, chan_regs + HOST1X_CHANNEL_DMAPUT);
- writel(0xFFFFFFFF, chan_regs + HOST1X_CHANNEL_DMAEND);
-
- /* reset GET */
- writel(nvhost_channel_dmactrl(true, true, true),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
-
- /* start the command DMA */
- writel(nvhost_channel_dmactrl(false, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
-
- cdma->running = true;
-}
-
-/**
- * Kick channel DMA into action by writing its PUT offset (if it has changed)
- */
-static void kick_cdma(struct nvhost_cdma *cdma)
-{
- u32 put = push_buffer_putptr(&cdma->push_buffer);
- if (put != cdma->last_put) {
- void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
- wmb();
- writel(put, chan_regs + HOST1X_CHANNEL_DMAPUT);
- cdma->last_put = put;
- }
-}
/**
* Return the status of the cdma's sync queue or push buffer for the given event
@@ -385,8 +232,11 @@ static unsigned int cdma_status(struct nvhost_cdma *cdma, enum cdma_event event)
return sync_queue_head(&cdma->sync_queue) ? 0 : 1;
case CDMA_EVENT_SYNC_QUEUE_SPACE:
return sync_queue_space(&cdma->sync_queue);
- case CDMA_EVENT_PUSH_BUFFER_SPACE:
- return push_buffer_space(&cdma->push_buffer);
+ 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);
+ }
default:
return 0;
}
@@ -401,7 +251,7 @@ static unsigned int cdma_status(struct nvhost_cdma *cdma, enum cdma_event event)
* - Return the amount of space (> 0)
* Must be called with the cdma lock held.
*/
-static unsigned int wait_cdma(struct nvhost_cdma *cdma, enum cdma_event event)
+unsigned int nvhost_cdma_wait(struct nvhost_cdma *cdma, enum cdma_event event)
{
for (;;) {
unsigned int space = cdma_status(cdma, event);
@@ -476,7 +326,9 @@ static void update_cdma(struct nvhost_cdma *cdma)
/* Pop push buffer slots */
if (nr_slots) {
- pop_from_push_buffer(&cdma->push_buffer, nr_slots);
+ struct push_buffer *pb = &cdma->push_buffer;
+ BUG_ON(!cdma_pb_op(cdma).pop_from);
+ cdma_pb_op(cdma).pop_from(pb, nr_slots);
if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
signal = true;
}
@@ -499,12 +351,20 @@ static void update_cdma(struct nvhost_cdma *cdma)
int nvhost_cdma_init(struct nvhost_cdma *cdma)
{
int err;
-
+ struct push_buffer *pb = &cdma->push_buffer;
+ BUG_ON(!cdma_pb_op(cdma).init);
mutex_init(&cdma->lock);
sema_init(&cdma->sem, 0);
cdma->event = CDMA_EVENT_NONE;
cdma->running = false;
- err = init_push_buffer(&cdma->push_buffer);
+
+ /* allocate sync queue memory */
+ cdma->sync_queue.buffer = kzalloc(cdma_to_dev(cdma)->sync_queue_size
+ * sizeof(u32), GFP_KERNEL);
+ if (!cdma->sync_queue.buffer)
+ return -ENOMEM;
+
+ err = cdma_pb_op(cdma).init(pb);
if (err)
return err;
reset_sync_queue(&cdma->sync_queue);
@@ -516,32 +376,24 @@ int nvhost_cdma_init(struct nvhost_cdma *cdma)
*/
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->running);
- destroy_push_buffer(&cdma->push_buffer);
+ kfree(cdma->sync_queue.buffer);
+ cdma->sync_queue.buffer = 0;
+ cdma_pb_op(cdma).destroy(pb);
}
-void nvhost_cdma_stop(struct nvhost_cdma *cdma)
-{
- void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
-
- mutex_lock(&cdma->lock);
- if (cdma->running) {
- wait_cdma(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY);
- writel(nvhost_channel_dmactrl(true, false, false),
- chan_regs + HOST1X_CHANNEL_DMACTRL);
- cdma->running = false;
- }
- mutex_unlock(&cdma->lock);
-}
/**
* Begin a cdma submit
*/
void nvhost_cdma_begin(struct nvhost_cdma *cdma)
{
+ BUG_ON(!cdma_op(cdma).start);
mutex_lock(&cdma->lock);
if (!cdma->running)
- start_cdma(cdma);
+ cdma_op(cdma).start(cdma);
cdma->slots_free = 0;
cdma->slots_used = 0;
}
@@ -553,13 +405,16 @@ void nvhost_cdma_begin(struct nvhost_cdma *cdma)
void nvhost_cdma_push(struct nvhost_cdma *cdma, 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);
if (slots_free == 0) {
- kick_cdma(cdma);
- slots_free = wait_cdma(cdma, CDMA_EVENT_PUSH_BUFFER_SPACE);
+ cdma_op(cdma).kick(cdma);
+ slots_free = nvhost_cdma_wait(cdma, CDMA_EVENT_PUSH_BUFFER_SPACE);
}
cdma->slots_free = slots_free - 1;
cdma->slots_used++;
- push_to_push_buffer(&cdma->push_buffer, op1, op2);
+ cdma_pb_op(cdma).push_to(pb, op1, op2);
}
/**
@@ -575,7 +430,8 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
u32 sync_point_id, u32 sync_point_value,
struct nvmap_handle **handles, unsigned int nr_handles)
{
- kick_cdma(cdma);
+ BUG_ON(!cdma_op(cdma).kick);
+ cdma_op(cdma).kick(cdma);
while (nr_handles || cdma->slots_used) {
unsigned int count;
@@ -583,7 +439,7 @@ void nvhost_cdma_end(struct nvhost_cdma *cdma,
* Wait until there's enough room in the
* sync queue to write something.
*/
- count = wait_cdma(cdma, CDMA_EVENT_SYNC_QUEUE_SPACE);
+ count = nvhost_cdma_wait(cdma, CDMA_EVENT_SYNC_QUEUE_SPACE);
/* Add reloc entries to sync queue (as many as will fit) */
if (count > nr_handles)
@@ -626,16 +482,3 @@ void nvhost_cdma_flush(struct nvhost_cdma *cdma)
mutex_unlock(&cdma->lock);
}
-/**
- * Retrieve the op pair at a slot offset from a DMA address
- */
-void nvhost_cdma_peek(struct nvhost_cdma *cdma,
- u32 dmaget, int slot, u32 *out)
-{
- u32 offset = dmaget - cdma->push_buffer.phys;
- u32 *p = cdma->push_buffer.mapped;
-
- offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
- out[0] = p[offset];
- out[1] = p[offset + 1];
-}
diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h
index a5876670a20a..64d17249f6af 100644
--- a/drivers/video/tegra/host/nvhost_cdma.h
+++ b/drivers/video/tegra/host/nvhost_cdma.h
@@ -45,13 +45,6 @@
* update - call to update sync queue and push buffer, unpin memory
*/
-/* Size of the sync queue. If it is too small, we won't be able to queue up
- * many command buffers. If it is too large, we waste memory. */
-#define NVHOST_SYNC_QUEUE_SIZE 8192
-
-/* Number of gathers we allow to be queued up per channel. Must be a
- power of two. Currently sized such that pushbuffer is 4KB (512*8B). */
-#define NVHOST_GATHER_QUEUE_SIZE 512
struct push_buffer {
struct nvmap_handle_ref *mem; /* handle to pushbuffer memory */
@@ -64,7 +57,7 @@ struct push_buffer {
struct sync_queue {
unsigned int read; /* read position within buffer */
unsigned int write; /* write position within buffer */
- u32 buffer[NVHOST_SYNC_QUEUE_SIZE]; /* queue data */
+ u32 *buffer; /* queue data */
};
enum cdma_event {
@@ -84,8 +77,17 @@ struct nvhost_cdma {
struct push_buffer push_buffer; /* channel's push buffer */
struct sync_queue sync_queue; /* channel's sync queue */
bool running;
+
};
+#define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
+#define cdma_to_dev(cdma) ((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);
@@ -100,4 +102,5 @@ void nvhost_cdma_flush(struct nvhost_cdma *cdma);
void nvhost_cdma_peek(struct nvhost_cdma *cdma,
u32 dmaget, int slot, u32 *out);
+unsigned int nvhost_cdma_wait(struct nvhost_cdma *cdma, enum cdma_event event);
#endif
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
index f7776e63e68d..ad8d403df0f7 100644
--- a/drivers/video/tegra/host/nvhost_channel.c
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -27,100 +27,7 @@
#include <linux/platform_device.h>
-#define NVMODMUTEX_2D_FULL (1)
-#define NVMODMUTEX_2D_SIMPLE (2)
-#define NVMODMUTEX_2D_SB_A (3)
-#define NVMODMUTEX_2D_SB_B (4)
-#define NVMODMUTEX_3D (5)
-#define NVMODMUTEX_DISPLAYA (6)
-#define NVMODMUTEX_DISPLAYB (7)
-#define NVMODMUTEX_VI (8)
-#define NVMODMUTEX_DSI (9)
-static void power_2d(struct nvhost_module *mod, enum nvhost_power_action action);
-static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action);
-static void power_mpe(struct nvhost_module *mod, enum nvhost_power_action action);
-
-static const struct nvhost_channeldesc channelmap[] = {
-{
- /* channel 0 */
- .name = "display",
- .syncpts = BIT(NVSYNCPT_DISP0) | BIT(NVSYNCPT_DISP1) |
- BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
- .modulemutexes = BIT(NVMODMUTEX_DISPLAYA) | BIT(NVMODMUTEX_DISPLAYB),
-},
-{
- /* channel 1 */
- .name = "gr3d",
- .syncpts = BIT(NVSYNCPT_3D),
- .waitbases = BIT(NVWAITBASE_3D),
- .modulemutexes = BIT(NVMODMUTEX_3D),
- .class = NV_GRAPHICS_3D_CLASS_ID,
- .power = power_3d,
-},
-{
- /* channel 2 */
- .name = "gr2d",
- .syncpts = BIT(NVSYNCPT_2D_0) | BIT(NVSYNCPT_2D_1),
- .waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
- .modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
- BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
- .power = power_2d,
-},
-{
- /* channel 3 */
- .name = "isp",
- .syncpts = 0,
-},
-{
- /* channel 4 */
- .name = "vi",
- .syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
- BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) |
- BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
- BIT(NVSYNCPT_VI_ISP_4),
- .modulemutexes = BIT(NVMODMUTEX_VI),
- .exclusive = true,
-},
-{
- /* channel 5 */
- .name = "mpe",
- .syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
- BIT(NVSYNCPT_MPE_WR_SAFE),
- .waitbases = BIT(NVWAITBASE_MPE),
- .class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
- .power = power_mpe,
- .exclusive = true,
- .keepalive = true,
-},
-{
- /* channel 6 */
- .name = "dsi",
- .syncpts = BIT(NVSYNCPT_DSI),
- .modulemutexes = BIT(NVMODMUTEX_DSI),
-}};
-
-static inline void __iomem *channel_aperture(void __iomem *p, int ndx)
-{
- ndx += NVHOST_CHANNEL_BASE;
- p += NV_HOST1X_CHANNEL0_BASE;
- p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
- return p;
-}
-
-int __init nvhost_channel_init(struct nvhost_channel *ch,
- struct nvhost_master *dev, int index)
-{
- BUILD_BUG_ON(NVHOST_NUMCHANNELS != ARRAY_SIZE(channelmap));
-
- ch->dev = dev;
- ch->desc = &channelmap[index];
- ch->aperture = channel_aperture(dev->aperture, index);
- mutex_init(&ch->reflock);
- mutex_init(&ch->submitlock);
-
- return nvhost_hwctx_handler_init(&ch->ctxhandler, ch->desc->name);
-}
struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
{
@@ -152,6 +59,8 @@ 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);
+
if (ctx) {
mutex_lock(&ch->submitlock);
if (ch->cur_ctx == ctx)
@@ -167,7 +76,8 @@ void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
if (ch->refcount == 1) {
nvhost_module_deinit(&ch->mod);
/* cdma may already be stopped, that's ok */
- nvhost_cdma_stop(&ch->cdma);
+
+ channel_cdma_op(ch).stop(&ch->cdma);
nvhost_cdma_deinit(&ch->cdma);
}
ch->refcount--;
@@ -178,211 +88,9 @@ void nvhost_channel_suspend(struct nvhost_channel *ch)
{
mutex_lock(&ch->reflock);
BUG_ON(nvhost_module_powered(&ch->mod));
+ BUG_ON(!channel_cdma_op(ch).stop);
+
if (ch->refcount)
- nvhost_cdma_stop(&ch->cdma);
+ channel_cdma_op(ch).stop(&ch->cdma);
mutex_unlock(&ch->reflock);
}
-
-int nvhost_channel_submit(struct nvhost_channel *channel,
- struct nvhost_hwctx *hwctx,
- struct nvmap_client *user_nvmap,
- u32 *gather,
- u32 *gather_end,
- struct nvhost_waitchk *waitchk,
- struct nvhost_waitchk *waitchk_end,
- u32 waitchk_mask,
- struct nvmap_handle **unpins,
- int nr_unpins,
- u32 syncpt_id,
- u32 syncpt_incrs,
- u32 *syncpt_value,
- bool null_kickoff)
-{
- struct nvhost_hwctx *hwctx_to_save = NULL;
- u32 user_syncpt_incrs = syncpt_incrs;
- bool need_restore = false;
- u32 syncval;
- int err;
-
- /* keep module powered */
- nvhost_module_busy(&channel->mod);
-
- /* get submit lock */
- err = mutex_lock_interruptible(&channel->submitlock);
- if (err) {
- nvhost_module_idle(&channel->mod);
- return err;
- }
-
- /* remove stale waits */
- if (waitchk != waitchk_end) {
- err = nvhost_syncpt_wait_check(user_nvmap,
- &channel->dev->syncpt, waitchk_mask,
- waitchk, waitchk_end);
- if (err) {
- dev_warn(&channel->dev->pdev->dev,
- "nvhost_syncpt_wait_check failed: %d\n", err);
- mutex_unlock(&channel->submitlock);
- nvhost_module_idle(&channel->mod);
- return err;
- }
- }
-
- /* context switch */
- if (channel->cur_ctx != hwctx) {
- trace_nvhost_channel_context_switch(channel->desc->name,
- channel->cur_ctx, hwctx);
- hwctx_to_save = channel->cur_ctx;
- if (hwctx_to_save) {
- syncpt_incrs += hwctx_to_save->save_incrs;
- hwctx_to_save->valid = true;
- channel->ctxhandler.get(hwctx_to_save);
- }
- channel->cur_ctx = hwctx;
- if (channel->cur_ctx && channel->cur_ctx->valid) {
- need_restore = true;
- syncpt_incrs += channel->cur_ctx->restore_incrs;
- }
- }
-
- /* get absolute sync value */
- if (BIT(syncpt_id) & NVSYNCPTS_CLIENT_MANAGED)
- syncval = nvhost_syncpt_set_max(&channel->dev->syncpt,
- syncpt_id, syncpt_incrs);
- else
- syncval = nvhost_syncpt_incr_max(&channel->dev->syncpt,
- syncpt_id, syncpt_incrs);
-
- /* begin a CDMA submit */
- nvhost_cdma_begin(&channel->cdma);
-
- /* push save buffer (pre-gather setup depends on unit) */
- if (hwctx_to_save)
- channel->ctxhandler.save_push(&channel->cdma, hwctx_to_save);
-
- /* gather restore buffer */
- if (need_restore)
- nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_gather(channel->cur_ctx->restore_size),
- channel->cur_ctx->restore_phys);
-
- /* add a setclass for modules that require it (unless ctxsw added it) */
- if (!hwctx_to_save && !need_restore && channel->desc->class)
- nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_setclass(channel->desc->class, 0, 0),
- NVHOST_OPCODE_NOOP);
-
- if (null_kickoff) {
- int incr;
- u32 op_incr;
-
- /* TODO ideally we'd also perform host waits here */
-
- /* push increments that correspond to nulled out commands */
- op_incr = nvhost_opcode_imm(0, 0x100 | syncpt_id);
- for (incr = 0; incr < (user_syncpt_incrs >> 1); incr++)
- nvhost_cdma_push(&channel->cdma, op_incr, op_incr);
- if (user_syncpt_incrs & 1)
- nvhost_cdma_push(&channel->cdma,
- op_incr, NVHOST_OPCODE_NOOP);
-
- /* for 3d, waitbase needs to be incremented after each submit */
- if (channel->desc->class == NV_GRAPHICS_3D_CLASS_ID)
- nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_setclass(
- NV_HOST1X_CLASS_ID,
- NV_CLASS_HOST_INCR_SYNCPT_BASE,
- 1),
- nvhost_class_host_incr_syncpt_base(
- NVWAITBASE_3D,
- user_syncpt_incrs));
- }
- else {
- /* push user gathers */
- for ( ; gather != gather_end; gather += 2)
- nvhost_cdma_push(&channel->cdma,
- nvhost_opcode_gather(gather[0]),
- gather[1]);
- }
-
- /* end CDMA submit & stash pinned hMems into sync queue */
- nvhost_cdma_end(&channel->cdma, user_nvmap,
- syncpt_id, syncval, unpins, nr_unpins);
-
- /*
- * schedule a context save interrupt (to drain the host FIFO
- * if necessary, and to release the restore buffer)
- */
- if (hwctx_to_save)
- nvhost_intr_add_action(&channel->dev->intr, syncpt_id,
- syncval - syncpt_incrs + hwctx_to_save->save_thresh,
- NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
-
- /* schedule a submit complete interrupt */
- nvhost_intr_add_action(&channel->dev->intr, syncpt_id, syncval,
- NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, NULL);
-
- mutex_unlock(&channel->submitlock);
-
- *syncpt_value = syncval;
- return 0;
-}
-
-static void power_2d(struct nvhost_module *mod, enum nvhost_power_action action)
-{
- /* TODO: [ahatala 2010-06-17] reimplement EPP hang war */
- if (action == NVHOST_POWER_ACTION_OFF) {
- /* TODO: [ahatala 2010-06-17] reset EPP */
- }
-}
-
-static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action)
-{
- struct nvhost_channel *ch = container_of(mod, struct nvhost_channel, mod);
- struct nvhost_hwctx *hwctx_to_save;
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
- u32 syncpt_incrs, syncpt_val;
- void *ref;
-
- if (action != NVHOST_POWER_ACTION_OFF)
- return;
-
- mutex_lock(&ch->submitlock);
- hwctx_to_save = ch->cur_ctx;
- if (!hwctx_to_save) {
- mutex_unlock(&ch->submitlock);
- return;
- }
-
- hwctx_to_save->valid = true;
- ch->ctxhandler.get(hwctx_to_save);
- ch->cur_ctx = NULL;
-
- syncpt_incrs = hwctx_to_save->save_incrs;
- syncpt_val = nvhost_syncpt_incr_max(&ch->dev->syncpt,
- NVSYNCPT_3D, syncpt_incrs);
-
- nvhost_cdma_begin(&ch->cdma);
- ch->ctxhandler.save_push(&ch->cdma, hwctx_to_save);
- nvhost_cdma_end(&ch->cdma, ch->dev->nvmap, NVSYNCPT_3D, syncpt_val, NULL, 0);
-
- nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D,
- syncpt_val - syncpt_incrs + hwctx_to_save->save_thresh,
- NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
-
- nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncpt_val,
- NVHOST_INTR_ACTION_WAKEUP, &wq, &ref);
- wait_event(wq,
- nvhost_syncpt_min_cmp(&ch->dev->syncpt,
- NVSYNCPT_3D, syncpt_val));
-
- nvhost_intr_put_ref(&ch->dev->intr, ref);
-
- nvhost_cdma_update(&ch->cdma);
-
- mutex_unlock(&ch->submitlock);
-}
-
-static void power_mpe(struct nvhost_module *mod, enum nvhost_power_action action)
-{
-}
diff --git a/drivers/video/tegra/host/nvhost_channel.h b/drivers/video/tegra/host/nvhost_channel.h
index b1515c4db6d9..2afd65d54b17 100644
--- a/drivers/video/tegra/host/nvhost_channel.h
+++ b/drivers/video/tegra/host/nvhost_channel.h
@@ -30,8 +30,6 @@
#include <linux/cdev.h>
#include <linux/io.h>
-#define NVHOST_CHANNEL_BASE 0
-#define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
#define NVHOST_MAX_WAIT_CHECKS 256
#define NVHOST_MAX_GATHERS 512
#define NVHOST_MAX_HANDLES 1280
@@ -98,4 +96,7 @@ struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch);
void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx);
void nvhost_channel_suspend(struct nvhost_channel *ch);
+#define channel_cdma_op(ch) (ch->dev->op.cdma)
+#define channel_op(ch) (ch->dev->op.channel)
+#define host_channel_op(host) (host->op.channel)
#endif
diff --git a/drivers/video/tegra/host/nvhost_cpuaccess.c b/drivers/video/tegra/host/nvhost_cpuaccess.c
index 4a5c34d593fc..dd585fbe8814 100644
--- a/drivers/video/tegra/host/nvhost_cpuaccess.c
+++ b/drivers/video/tegra/host/nvhost_cpuaccess.c
@@ -24,20 +24,20 @@
#include "dev.h"
#include <linux/string.h>
-#define cpuaccess_to_dev(ctx) container_of(ctx, struct nvhost_master, cpuaccess)
-
int nvhost_cpuaccess_init(struct nvhost_cpuaccess *ctx,
struct platform_device *pdev)
{
+ struct nvhost_master *host = cpuaccess_to_dev(ctx);
int i;
- for (i = 0; i < NVHOST_MODULE_NUM; i++) {
+
+ for (i = 0; i < host->nb_modules; i++) {
struct resource *mem;
mem = platform_get_resource(pdev, IORESOURCE_MEM, i+1);
if (!mem) {
dev_err(&pdev->dev, "missing module memory resource\n");
return -ENXIO;
}
-
+ ctx->reg_mem[i] = mem;
ctx->regs[i] = ioremap(mem->start, resource_size(mem));
if (!ctx->regs[i]) {
dev_err(&pdev->dev, "failed to map module registers\n");
@@ -50,8 +50,10 @@ int nvhost_cpuaccess_init(struct nvhost_cpuaccess *ctx,
void nvhost_cpuaccess_deinit(struct nvhost_cpuaccess *ctx)
{
+ struct nvhost_master *host = cpuaccess_to_dev(ctx);
int i;
- for (i = 0; i < NVHOST_MODULE_NUM; i++) {
+
+ for (i = 0; i < host->nb_modules; i++) {
iounmap(ctx->regs[i]);
release_resource(ctx->reg_mem[i]);
}
@@ -60,13 +62,11 @@ void nvhost_cpuaccess_deinit(struct nvhost_cpuaccess *ctx)
int nvhost_mutex_try_lock(struct nvhost_cpuaccess *ctx, unsigned int idx)
{
struct nvhost_master *dev = cpuaccess_to_dev(ctx);
- void __iomem *sync_regs = dev->sync_aperture;
u32 reg;
+ BUG_ON(!cpuaccess_op(ctx).mutex_try_lock);
- /* mlock registers returns 0 when the lock is aquired.
- * writing 0 clears the lock. */
nvhost_module_busy(&dev->mod);
- reg = readl(sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
+ reg = cpuaccess_op(ctx).mutex_try_lock(ctx, idx);
if (reg) {
nvhost_module_idle(&dev->mod);
return -ERESTARTSYS;
@@ -78,8 +78,9 @@ int nvhost_mutex_try_lock(struct nvhost_cpuaccess *ctx, unsigned int idx)
void nvhost_mutex_unlock(struct nvhost_cpuaccess *ctx, unsigned int idx)
{
struct nvhost_master *dev = cpuaccess_to_dev(ctx);
- void __iomem *sync_regs = dev->sync_aperture;
- writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
+ BUG_ON(!cpuaccess_op(ctx).mutex_unlock);
+
+ cpuaccess_op(ctx).mutex_unlock(ctx, idx);
nvhost_module_idle(&dev->mod);
atomic_dec(&ctx->lock_counts[idx]);
}
diff --git a/drivers/video/tegra/host/nvhost_cpuaccess.h b/drivers/video/tegra/host/nvhost_cpuaccess.h
index 98ea1e1e1f8f..2e210b7477af 100644
--- a/drivers/video/tegra/host/nvhost_cpuaccess.h
+++ b/drivers/video/tegra/host/nvhost_cpuaccess.h
@@ -23,7 +23,6 @@
#ifndef __NVHOST_CPUACCESS_H
#define __NVHOST_CPUACCESS_H
-#include "nvhost_hardware.h"
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -43,26 +42,20 @@ enum nvhost_module_id {
};
struct nvhost_cpuaccess {
- struct resource *reg_mem[NVHOST_MODULE_NUM];
- void __iomem *regs[NVHOST_MODULE_NUM];
- atomic_t lock_counts[NV_HOST1X_SYNC_MLOCK_NUM];
+ struct resource **reg_mem;
+ void __iomem **regs;
+ atomic_t *lock_counts;
};
+#define cpuaccess_to_dev(ctx) container_of(ctx, struct nvhost_master, cpuaccess)
+#define cpuaccess_op(ctx) (cpuaccess_to_dev(ctx)->op.cpuaccess)
int nvhost_cpuaccess_init(struct nvhost_cpuaccess *ctx,
struct platform_device *pdev);
-void nvhost_cpuaccess_deinit(struct nvhost_cpuaccess *ctx);
-
int nvhost_mutex_try_lock(struct nvhost_cpuaccess *ctx, unsigned int idx);
void nvhost_mutex_unlock(struct nvhost_cpuaccess *ctx, unsigned int idx);
-static inline bool nvhost_access_module_regs(
- struct nvhost_cpuaccess *ctx, u32 module)
-{
- return (module < NVHOST_MODULE_NUM);
-}
-
void nvhost_read_module_regs(struct nvhost_cpuaccess *ctx, u32 module,
u32 offset, size_t size, void *values);
diff --git a/drivers/video/tegra/host/nvhost_hwctx.h b/drivers/video/tegra/host/nvhost_hwctx.h
index 67c3c7f8d0ce..83d93bd871eb 100644
--- a/drivers/video/tegra/host/nvhost_hwctx.h
+++ b/drivers/video/tegra/host/nvhost_hwctx.h
@@ -57,20 +57,6 @@ struct nvhost_hwctx_handler {
void (*save_service) (struct nvhost_hwctx *ctx);
};
-int nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h);
-int nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h);
-
-static inline int nvhost_hwctx_handler_init(
- struct nvhost_hwctx_handler *h,
- const char *module)
-{
- if (strcmp(module, "gr3d") == 0)
- return nvhost_3dctx_handler_init(h);
- else if (strcmp(module, "mpe") == 0)
- return nvhost_mpectx_handler_init(h);
-
- return 0;
-}
struct hwctx_reginfo {
unsigned int offset:12;
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index 729a0e351453..ef511392154b 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -26,52 +26,8 @@
#include <linux/slab.h>
#include <linux/irq.h>
-#define intr_to_dev(x) container_of(x, struct nvhost_master, intr)
-/*** HW host sync management ***/
-
-void init_host_sync(void __iomem *sync_regs)
-{
- /* disable the ip_busy_timeout. this prevents write drops, etc.
- * there's no real way to recover from a hung client anyway.
- */
- writel(0, sync_regs + HOST1X_SYNC_IP_BUSY_TIMEOUT);
-
- /* increase the auto-ack timout to the maximum value. 2d will hang
- * otherwise on ap20.
- */
- writel(0xff, sync_regs + HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
-}
-
-void set_host_clocks_per_microsecond(void __iomem *sync_regs, u32 cpm)
-{
- /* write microsecond clock register */
- writel(cpm, sync_regs + HOST1X_SYNC_USEC_CLK);
-}
-
-static void set_syncpt_threshold(void __iomem *sync_regs, u32 id, u32 thresh)
-{
- thresh &= 0xffff;
- writel(thresh, sync_regs + (HOST1X_SYNC_SYNCPT_INT_THRESH_0 + id * 4));
-}
-
-static void enable_syncpt_interrupt(void __iomem *sync_regs, u32 id)
-{
- writel(BIT(id), sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0);
-}
-
-void disable_all_syncpt_interrupts(void __iomem *sync_regs)
-{
- /* disable interrupts for both cpu's */
- writel(0, sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
-
- /* clear status for both cpu's */
- writel(0xfffffffful, sync_regs +
- HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
- writel(0xfffffffful, sync_regs +
- HOST1X_SYNC_SYNCPT_THRESH_CPU1_INT_STATUS);
-}
/*** Wait list management ***/
@@ -156,14 +112,17 @@ static void remove_completed_waiters(struct list_head *head, u32 sync,
}
}
-void reset_threshold_interrupt(struct list_head *head,
- unsigned int id, void __iomem *sync_regs)
+void reset_threshold_interrupt(struct nvhost_intr *intr,
+ struct list_head *head,
+ unsigned int id)
{
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));
- set_syncpt_threshold(sync_regs, id, thresh);
- enable_syncpt_interrupt(sync_regs, id);
+ intr_op(intr).set_syncpt_threshold(intr, id, thresh);
+ intr_op(intr).enable_syncpt_intr(intr, id);
}
@@ -230,8 +189,9 @@ static void run_handlers(struct list_head completed[NVHOST_INTR_ACTION_COUNT])
/**
* Remove & handle all waiters that have completed for the given syncpt
*/
-static int process_wait_list(struct nvhost_intr_syncpt *syncpt,
- u32 threshold, void __iomem *sync_regs)
+static int process_wait_list(struct nvhost_intr *intr,
+ struct nvhost_intr_syncpt *syncpt,
+ u32 threshold)
{
struct list_head completed[NVHOST_INTR_ACTION_COUNT];
unsigned int i;
@@ -246,8 +206,8 @@ static int process_wait_list(struct nvhost_intr_syncpt *syncpt,
empty = list_empty(&syncpt->wait_head);
if (!empty)
- reset_threshold_interrupt(&syncpt->wait_head,
- syncpt->id, sync_regs);
+ reset_threshold_interrupt(intr, &syncpt->wait_head,
+ syncpt->id);
spin_unlock(&syncpt->lock);
@@ -256,29 +216,7 @@ static int process_wait_list(struct nvhost_intr_syncpt *syncpt,
return empty;
}
-
/*** host syncpt interrupt service functions ***/
-
-/**
- * Sync point threshold interrupt service function
- * Handles sync point threshold triggers, in interrupt context
- */
-static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
-{
- struct nvhost_intr_syncpt *syncpt = dev_id;
- unsigned int id = syncpt->id;
- struct nvhost_intr *intr = container_of(syncpt, struct nvhost_intr,
- syncpt[id]);
- void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
-
- writel(BIT(id),
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
- writel(BIT(id),
- sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
-
- return IRQ_WAKE_THREAD;
-}
-
/**
* Sync point threshold interrupt service thread function
* Handles sync point threshold triggers, in thread context
@@ -287,13 +225,11 @@ static irqreturn_t syncpt_thresh_fn(int irq, void *dev_id)
{
struct nvhost_intr_syncpt *syncpt = dev_id;
unsigned int id = syncpt->id;
- struct nvhost_intr *intr = container_of(syncpt, struct nvhost_intr,
- syncpt[id]);
+ struct nvhost_intr *intr = intr_syncpt_to_intr(syncpt);
struct nvhost_master *dev = intr_to_dev(intr);
- (void)process_wait_list(syncpt,
- nvhost_syncpt_update_min(&dev->syncpt, id),
- dev->sync_aperture);
+ (void)process_wait_list(intr, syncpt,
+ nvhost_syncpt_update_min(&dev->syncpt, id));
return IRQ_HANDLED;
}
@@ -304,12 +240,12 @@ static irqreturn_t syncpt_thresh_fn(int irq, void *dev_id)
static int request_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
{
int err;
-
+ extern irqreturn_t t20_intr_syncpt_thresh_isr(int irq, void *dev_id);
if (syncpt->irq_requested)
return 0;
err = request_threaded_irq(syncpt->irq,
- syncpt_thresh_isr, syncpt_thresh_fn,
+ t20_intr_syncpt_thresh_isr, syncpt_thresh_fn,
0, syncpt->thresh_irq_name, syncpt);
if (err)
return err;
@@ -332,87 +268,6 @@ static void free_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
/*** host general interrupt service functions ***/
-/**
- * Host general interrupt service function
- * Handles read / write failures
- */
-static irqreturn_t host1x_isr(int irq, void *dev_id)
-{
- struct nvhost_intr *intr = dev_id;
- void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
- u32 stat;
- u32 ext_stat;
- u32 addr;
-
- stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS);
- ext_stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
-
- if (nvhost_sync_hintstatus_ext_ip_read_int(ext_stat)) {
- addr = readl(sync_regs + HOST1X_SYNC_IP_READ_TIMEOUT_ADDR);
- pr_err("Host read timeout at address %x\n", addr);
- }
-
- if (nvhost_sync_hintstatus_ext_ip_write_int(ext_stat)) {
- addr = readl(sync_regs + HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR);
- pr_err("Host write timeout at address %x\n", addr);
- }
-
- writel(ext_stat, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
- writel(stat, sync_regs + HOST1X_SYNC_HINTSTATUS);
-
- return IRQ_HANDLED;
-}
-
-static int request_host_general_irq(struct nvhost_intr *intr)
-{
- void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
- int err;
-
- if (intr->host_general_irq_requested)
- return 0;
-
- /* master disable for general (not syncpt) host interrupts */
- writel(0, sync_regs + HOST1X_SYNC_INTMASK);
-
- /* clear status & extstatus */
- writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
- writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS);
-
- err = request_irq(intr->host_general_irq, host1x_isr, 0,
- "host_status", intr);
- if (err)
- return err;
-
- /* enable extra interrupt sources IP_READ_INT and IP_WRITE_INT */
- writel(BIT(30) | BIT(31), sync_regs + HOST1X_SYNC_HINTMASK_EXT);
-
- /* enable extra interrupt sources */
- writel(BIT(31), sync_regs + HOST1X_SYNC_HINTMASK);
-
- /* enable host module interrupt to CPU0 */
- writel(BIT(0), sync_regs + HOST1X_SYNC_INTC0MASK);
-
- /* master enable for general (not syncpt) host interrupts */
- writel(BIT(0), sync_regs + HOST1X_SYNC_INTMASK);
-
- intr->host_general_irq_requested = true;
-
- return err;
-}
-
-static void free_host_general_irq(struct nvhost_intr *intr)
-{
- if (intr->host_general_irq_requested) {
- void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
-
- /* master disable for general (not syncpt) host interrupts */
- writel(0, sync_regs + HOST1X_SYNC_INTMASK);
-
- free_irq(intr->host_general_irq, intr);
- intr->host_general_irq_requested = false;
- }
-}
-
/*** Main API ***/
@@ -422,10 +277,12 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
{
struct nvhost_waitlist *waiter;
struct nvhost_intr_syncpt *syncpt;
- void __iomem *sync_regs;
int queue_was_empty;
int err;
+ BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
+ intr_op(intr).enable_syncpt_intr));
+
/* create and initialize a new waiter */
waiter = kmalloc(sizeof(*waiter), GFP_KERNEL);
if (!waiter)
@@ -440,9 +297,8 @@ int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
waiter->data = data;
waiter->count = 1;
- BUG_ON(id >= NV_HOST1X_SYNCPT_NB_PTS);
+ BUG_ON(id >= intr_to_dev(intr)->syncpt.nb_pts);
syncpt = intr->syncpt + id;
- sync_regs = intr_to_dev(intr)->sync_aperture;
spin_lock(&syncpt->lock);
@@ -466,11 +322,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 */
- set_syncpt_threshold(sync_regs, id, thresh);
+ intr_op(intr).set_syncpt_threshold(intr, id, thresh);
/* added as first waiter - enable interrupt */
if (queue_was_empty)
- enable_syncpt_interrupt(sync_regs, id);
+ intr_op(intr).enable_syncpt_intr(intr, id);
}
spin_unlock(&syncpt->lock);
@@ -498,14 +354,18 @@ int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync)
{
unsigned int id;
struct nvhost_intr_syncpt *syncpt;
+ struct nvhost_master *host =
+ container_of(intr, struct nvhost_master, intr);
+ u32 nb_pts = host->syncpt.nb_pts;
mutex_init(&intr->mutex);
intr->host_general_irq = irq_gen;
intr->host_general_irq_requested = false;
for (id = 0, syncpt = intr->syncpt;
- id < NV_HOST1X_SYNCPT_NB_PTS;
+ id < nb_pts;
++id, ++syncpt) {
+ syncpt->intr = &host->intr;
syncpt->id = id;
syncpt->irq = irq_sync + id;
syncpt->irq_requested = 0;
@@ -526,31 +386,36 @@ void nvhost_intr_deinit(struct nvhost_intr *intr)
void nvhost_intr_start(struct nvhost_intr *intr, u32 hz)
{
- struct nvhost_master *dev = intr_to_dev(intr);
- void __iomem *sync_regs = dev->sync_aperture;
+ BUG_ON(!(intr_op(intr).init_host_sync &&
+ intr_op(intr).set_host_clocks_per_usec &&
+ intr_op(intr).request_host_general_irq));
mutex_lock(&intr->mutex);
- init_host_sync(sync_regs);
- set_host_clocks_per_microsecond(sync_regs, (hz + 1000000 - 1)/1000000);
+ intr_op(intr).init_host_sync(intr);
+ intr_op(intr).set_host_clocks_per_usec(intr,
+ (hz + 1000000 - 1)/1000000);
- request_host_general_irq(intr);
+ intr_op(intr).request_host_general_irq(intr);
mutex_unlock(&intr->mutex);
}
void nvhost_intr_stop(struct nvhost_intr *intr)
{
- void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
unsigned int id;
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));
mutex_lock(&intr->mutex);
- disable_all_syncpt_interrupts(sync_regs);
+ intr_op(intr).disable_all_syncpt_intrs(intr);
for (id = 0, syncpt = intr->syncpt;
- id < NV_HOST1X_SYNCPT_NB_PTS;
+ id < nb_pts;
++id, ++syncpt) {
struct nvhost_waitlist *waiter, *next;
list_for_each_entry_safe(waiter, next, &syncpt->wait_head, list) {
@@ -569,7 +434,7 @@ void nvhost_intr_stop(struct nvhost_intr *intr)
free_syncpt_irq(syncpt);
}
- free_host_general_irq(intr);
+ intr_op(intr).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 fb3e613d70da..150fd6c5694c 100644
--- a/drivers/video/tegra/host/nvhost_intr.h
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -26,8 +26,6 @@
#include <linux/kthread.h>
#include <linux/semaphore.h>
-#include "nvhost_hardware.h"
-
struct nvhost_channel;
enum nvhost_intr_action {
@@ -58,7 +56,10 @@ enum nvhost_intr_action {
NVHOST_INTR_ACTION_COUNT
};
+struct nvhost_intr;
+
struct nvhost_intr_syncpt {
+ struct nvhost_intr *intr;
u8 id;
u8 irq_requested;
u16 irq;
@@ -68,11 +69,14 @@ struct nvhost_intr_syncpt {
};
struct nvhost_intr {
- struct nvhost_intr_syncpt syncpt[NV_HOST1X_SYNCPT_NB_PTS];
+ struct nvhost_intr_syncpt *syncpt;
struct mutex mutex;
int host_general_irq;
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
/**
* Schedule an action to be taken when a sync point reaches the given threshold.
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 942030865f4b..88059b0f182d 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -23,51 +23,6 @@
#include "nvhost_syncpt.h"
#include "dev.h"
-#define client_managed(id) (BIT(id) & NVSYNCPTS_CLIENT_MANAGED)
-#define syncpt_to_dev(sp) container_of(sp, struct nvhost_master, syncpt)
-#define SYNCPT_CHECK_PERIOD 2*HZ
-
-static bool check_max(struct nvhost_syncpt *sp, u32 id, u32 real)
-{
- u32 max;
- if (client_managed(id))
- return true;
- smp_rmb();
- max = (u32)atomic_read(&sp->max_val[id]);
- return ((s32)(max - real) >= 0);
-}
-
-/**
- * Write the current syncpoint value back to hw.
- */
-static void reset_syncpt(struct nvhost_syncpt *sp, u32 id)
-{
- struct nvhost_master *dev = syncpt_to_dev(sp);
- int min;
- smp_rmb();
- min = atomic_read(&sp->min_val[id]);
- writel(min, dev->sync_aperture + (HOST1X_SYNC_SYNCPT_0 + id * 4));
-}
-
-/**
- * Write the current waitbase value back to hw.
- */
-static void reset_syncpt_wait_base(struct nvhost_syncpt *sp, u32 id)
-{
- struct nvhost_master *dev = syncpt_to_dev(sp);
- writel(sp->base_val[id],
- dev->sync_aperture + (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
-}
-
-/**
- * Read waitbase value from hw.
- */
-static void read_syncpt_wait_base(struct nvhost_syncpt *sp, u32 id)
-{
- struct nvhost_master *dev = syncpt_to_dev(sp);
- sp->base_val[id] = readl(dev->sync_aperture +
- (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
-}
/**
* Resets syncpoint and waitbase values to sw shadows
@@ -75,10 +30,12 @@ static void read_syncpt_wait_base(struct nvhost_syncpt *sp, u32 id)
void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
{
u32 i;
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++)
- reset_syncpt(sp, i);
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_BASES; i++)
- reset_syncpt_wait_base(sp, i);
+ BUG_ON(!(syncpt_op(sp).reset && syncpt_op(sp).reset_wait_base));
+
+ for (i = 0; i < sp->nb_pts; i++)
+ syncpt_op(sp).reset(sp, i);
+ for (i = 0; i < sp->nb_bases; i++)
+ syncpt_op(sp).reset_wait_base(sp, i);
wmb();
}
@@ -88,16 +45,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));
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
+ for (i = 0; i < sp->nb_pts; i++) {
if (client_managed(i))
- nvhost_syncpt_update_min(sp, i);
+ syncpt_op(sp).update_min(sp, i);
else
BUG_ON(!nvhost_syncpt_min_eq_max(sp, i));
}
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_BASES; i++)
- read_syncpt_wait_base(sp, i);
+ for (i = 0; i < sp->nb_bases; i++)
+ syncpt_op(sp).read_wait_base(sp, i);
}
/**
@@ -105,19 +63,9 @@ void nvhost_syncpt_save(struct nvhost_syncpt *sp)
*/
u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
{
- struct nvhost_master *dev = syncpt_to_dev(sp);
- void __iomem *sync_regs = dev->sync_aperture;
- u32 old, live;
-
- do {
- smp_rmb();
- old = (u32)atomic_read(&sp->min_val[id]);
- live = readl(sync_regs + (HOST1X_SYNC_SYNCPT_0 + id * 4));
- } while ((u32)atomic_cmpxchg(&sp->min_val[id], old, live) != old);
-
- BUG_ON(!check_max(sp, id, live));
+ BUG_ON(!syncpt_op(sp).update_min);
- return live;
+ return syncpt_op(sp).update_min(sp, id);
}
/**
@@ -126,9 +74,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);
nvhost_module_busy(&syncpt_to_dev(sp)->mod);
- val = nvhost_syncpt_update_min(sp, id);
+ val = syncpt_op(sp).update_min(sp, id);
nvhost_module_idle(&syncpt_to_dev(sp)->mod);
return val;
}
@@ -139,11 +87,8 @@ u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
*/
void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
{
- struct nvhost_master *dev = syncpt_to_dev(sp);
- BUG_ON(!nvhost_module_powered(&dev->mod));
- BUG_ON(!client_managed(id) && nvhost_syncpt_min_eq_max(sp, id));
- writel(BIT(id), dev->sync_aperture + HOST1X_SYNC_SYNCPT_CPU_INCR);
- wmb();
+ BUG_ON(!syncpt_op(sp).cpu_incr);
+ syncpt_op(sp).cpu_incr(sp, id);
}
/**
@@ -169,8 +114,8 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
if (value)
*value = 0;
-
- BUG_ON(!check_max(sp, id, thresh));
+ BUG_ON(!syncpt_op(sp).update_min);
+ BUG_ON(!nvhost_syncpt_check_max(sp, id, thresh));
/* first check cache */
if (nvhost_syncpt_min_cmp(sp, id, thresh)) {
@@ -184,7 +129,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
if (client_managed(id) || !nvhost_syncpt_min_eq_max(sp, id)) {
/* try to read from register */
- u32 val = nvhost_syncpt_update_min(sp, id);
+ u32 val = syncpt_op(sp).update_min(sp, id);
if ((s32)(val - thresh) >= 0) {
if (value)
*value = val;
@@ -225,8 +170,8 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
if (timeout) {
dev_warn(&syncpt_to_dev(sp)->pdev->dev,
"syncpoint id %d (%s) stuck waiting %d\n",
- id, nvhost_syncpt_name(id), thresh);
- nvhost_syncpt_debug(sp);
+ id, syncpt_op(sp).name(sp, id), thresh);
+ syncpt_op(sp).debug(sp);
}
}
nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), ref);
@@ -236,98 +181,17 @@ done:
return err;
}
-static const char *s_syncpt_names[32] = {
- "gfx_host", "", "", "", "", "", "", "", "", "", "",
- "csi_vi_0", "csi_vi_1", "vi_isp_0", "vi_isp_1", "vi_isp_2", "vi_isp_3", "vi_isp_4",
- "2d_0", "2d_1",
- "", "",
- "3d", "mpe", "disp0", "disp1", "vblank0", "vblank1", "mpe_ebm_eof", "mpe_wr_safe",
- "2d_tinyblt", "dsi"
-};
-
-const char *nvhost_syncpt_name(u32 id)
-{
- BUG_ON(id > ARRAY_SIZE(s_syncpt_names));
- return s_syncpt_names[id];
-}
-
void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
{
- u32 i;
- for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
- u32 max = nvhost_syncpt_read_max(sp, i);
- if (!max)
- continue;
- dev_info(&syncpt_to_dev(sp)->pdev->dev,
- "id %d (%s) min %d max %d\n",
- i, nvhost_syncpt_name(i),
- nvhost_syncpt_update_min(sp, i), max);
-
- }
-}
-
-/* returns true, if a <= b < c using wrapping comparison */
-static inline bool nvhost_syncpt_is_between(u32 a, u32 b, u32 c)
-{
- return b-a < c-a;
-}
-
-/* returns true, if syncpt >= threshold (mod 1 << 32) */
-static bool nvhost_syncpt_wrapping_comparison(u32 syncpt, u32 threshold)
-{
- return nvhost_syncpt_is_between(threshold, syncpt,
- (1UL<<31UL)+threshold);
+ syncpt_op(sp).debug(sp);
}
/* check for old WAITs to be removed (avoiding a wrap) */
-int nvhost_syncpt_wait_check(struct nvmap_client *nvmap,
- struct nvhost_syncpt *sp, u32 waitchk_mask,
- struct nvhost_waitchk *wait,
- struct nvhost_waitchk *waitend)
+int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
+ struct nvmap_client *nvmap,
+ u32 waitchk_mask,
+ struct nvhost_waitchk *wait,
+ struct nvhost_waitchk *waitend)
{
- u32 idx;
- int err = 0;
-
- /* get current syncpt values */
- for (idx = 0; idx < NV_HOST1X_SYNCPT_NB_PTS; idx++) {
- if (BIT(idx) & waitchk_mask)
- nvhost_syncpt_update_min(sp, idx);
- }
-
- BUG_ON(!wait && !waitend);
-
- /* compare syncpt vs wait threshold */
- while (wait != waitend) {
- u32 syncpt, override;
-
- BUG_ON(wait->syncpt_id > NV_HOST1X_SYNCPT_NB_PTS);
-
- syncpt = atomic_read(&sp->min_val[wait->syncpt_id]);
- if (nvhost_syncpt_wrapping_comparison(syncpt, wait->thresh)) {
- /*
- * NULL an already satisfied WAIT_SYNCPT host method,
- * by patching its args in the command stream. The
- * method data is changed to reference a reserved
- * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
- * syncpt with a matching threshold value of 0, so
- * is guaranteed to be popped by the host HW.
- */
- dev_dbg(&syncpt_to_dev(sp)->pdev->dev,
- "drop WAIT id %d (%s) thresh 0x%x, syncpt 0x%x\n",
- wait->syncpt_id,
- nvhost_syncpt_name(wait->syncpt_id),
- wait->thresh, syncpt);
-
- /* patch the wait */
- override = nvhost_class_host_wait_syncpt(
- NVSYNCPT_GRAPHICS_HOST, 0);
- err = nvmap_patch_word(nvmap,
- (struct nvmap_handle *)wait->mem,
- wait->offset, override);
- if (err)
- break;
- }
- wait++;
- }
- return err;
+ return syncpt_op(sp).wait_check(sp, nvmap, waitchk_mask, wait, waitend);
}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h
index 564cc83a954f..b6db72e915a9 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.h
+++ b/drivers/video/tegra/host/nvhost_syncpt.h
@@ -29,54 +29,35 @@
#include <mach/nvmap.h>
#include <asm/atomic.h>
-#include "nvhost_hardware.h"
-
+/* host managed and invalid syncpt id */
#define NVSYNCPT_GRAPHICS_HOST (0)
-#define NVSYNCPT_CSI_VI_0 (11)
-#define NVSYNCPT_CSI_VI_1 (12)
-#define NVSYNCPT_VI_ISP_0 (13)
-#define NVSYNCPT_VI_ISP_1 (14)
-#define NVSYNCPT_VI_ISP_2 (15)
-#define NVSYNCPT_VI_ISP_3 (16)
-#define NVSYNCPT_VI_ISP_4 (17)
-#define NVSYNCPT_2D_0 (18)
-#define NVSYNCPT_2D_1 (19)
-#define NVSYNCPT_3D (22)
-#define NVSYNCPT_MPE (23)
-#define NVSYNCPT_DISP0 (24)
-#define NVSYNCPT_DISP1 (25)
-#define NVSYNCPT_VBLANK0 (26)
-#define NVSYNCPT_VBLANK1 (27)
-#define NVSYNCPT_MPE_EBM_EOF (28)
-#define NVSYNCPT_MPE_WR_SAFE (29)
-#define NVSYNCPT_DSI (31)
#define NVSYNCPT_INVALID (-1)
-/*#define NVSYNCPT_2D_CHANNEL2_0 (20) */
-/*#define NVSYNCPT_2D_CHANNEL2_1 (21) */
-/*#define NVSYNCPT_2D_TINYBLT_WAR (30)*/
-/*#define NVSYNCPT_2D_TINYBLT_RESTORE_CLASS_ID (30)*/
-
-/* sync points that are wholly managed by the client */
-#define NVSYNCPTS_CLIENT_MANAGED ( \
- BIT(NVSYNCPT_DISP0) | BIT(NVSYNCPT_DISP1) | BIT(NVSYNCPT_DSI) | \
- BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) | \
- BIT(NVSYNCPT_VI_ISP_1) | BIT(NVSYNCPT_VI_ISP_2) | \
- BIT(NVSYNCPT_VI_ISP_3) | BIT(NVSYNCPT_VI_ISP_4) | \
- BIT(NVSYNCPT_MPE_EBM_EOF) | BIT(NVSYNCPT_MPE_WR_SAFE) | \
- BIT(NVSYNCPT_2D_1))
-
-#define NVWAITBASE_2D_0 (1)
-#define NVWAITBASE_2D_1 (2)
-#define NVWAITBASE_3D (3)
-#define NVWAITBASE_MPE (4)
-
struct nvhost_syncpt {
- atomic_t min_val[NV_HOST1X_SYNCPT_NB_PTS];
- atomic_t max_val[NV_HOST1X_SYNCPT_NB_PTS];
- u32 base_val[NV_HOST1X_SYNCPT_NB_BASES];
+ atomic_t *min_val;
+ atomic_t *max_val;
+ u32 *base_val;
+ u32 nb_pts;
+ u32 nb_bases;
+ u32 client_managed;
};
+int nvhost_syncpt_init(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
+static inline bool nvhost_syncpt_check_max(struct nvhost_syncpt *sp, u32 id, u32 real)
+{
+ u32 max;
+ if (client_managed(id))
+ return true;
+ smp_rmb();
+ max = (u32)atomic_read(&sp->max_val[id]);
+ return ((s32)(max - real) >= 0);
+}
+
+
/**
* Updates the value sent to hardware.
*/
@@ -159,14 +140,15 @@ static inline int nvhost_syncpt_wait(struct nvhost_syncpt *sp, u32 id, u32 thres
* that have already been satisfied and NULL the comparison (to
* avoid a wrap condition in the HW).
*
- * @param: nvmap - needed to access command buffer
* @param: sp - global shadowed syncpt struct
+ * @param: nvmap - needed to access command buffer
* @param: mask - bit mask of syncpt IDs referenced in WAITs
* @param: wait - start of filled in array of waitchk structs
* @param: waitend - end ptr (one beyond last valid waitchk)
*/
-int nvhost_syncpt_wait_check(struct nvmap_client *nvmap,
- struct nvhost_syncpt *sp, u32 mask,
+int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
+ struct nvmap_client *nvmap,
+ u32 mask,
struct nvhost_waitchk *wait,
struct nvhost_waitchk *waitend);
diff --git a/drivers/video/tegra/host/nvhost_3dctx.c b/drivers/video/tegra/host/t20/3dctx_t20.c
index ecbca73454aa..b9068b03f78e 100644
--- a/drivers/video/tegra/host/nvhost_3dctx.c
+++ b/drivers/video/tegra/host/t20/3dctx_t20.c
@@ -1,5 +1,5 @@
/*
- * drivers/video/tegra/host/nvhost_3dctx.c
+ * drivers/video/tegra/host/t20/3dctx_t20.c
*
* Tegra Graphics Host 3d hardware context
*
@@ -20,13 +20,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "nvhost_hwctx.h"
-#include "dev.h"
+#include "../nvhost_hwctx.h"
+#include "../dev.h"
+#include "hardware_t20.h"
+#include "syncpt_t20.h"
#include <mach/gpufuse.h>
#include <mach/hardware.h>
#include <linux/slab.h>
+
#define NV_WAR_789194 1
/* 99 > 2, which makes kernel panic if register set is incorrect */
@@ -38,6 +41,8 @@ static bool s_is_v1 = true;
#endif
static bool s_war_insert_syncpoints;
+
+
const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
HWCTX_REGINFO(0, 0xe00, 4, DIRECT),
HWCTX_REGINFO(0, 0xe05, 30, DIRECT),
@@ -769,10 +774,7 @@ static const struct ctx_saver v1_saver __initconst = {
.ctx3d_save_service = NULL
};
-
-/*** nvhost_3dctx ***/
-
-int __init nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
+int __init t20_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
{
const struct ctx_saver *saver = s_is_v1 ? &v1_saver : &v0_saver;
struct nvhost_channel *ch;
@@ -819,7 +821,7 @@ int __init nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h)
}
/* TODO: [ahatala 2010-05-27] */
-int __init nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h)
+int __init t20_nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h)
{
return 0;
}
diff --git a/drivers/video/tegra/host/t20/Makefile b/drivers/video/tegra/host/t20/Makefile
new file mode 100644
index 000000000000..a4d404074d0c
--- /dev/null
+++ b/drivers/video/tegra/host/t20/Makefile
@@ -0,0 +1,11 @@
+nvhost-t20-objs = \
+ t20.o \
+ syncpt_t20.o \
+ cpuaccess_t20.o \
+ channel_t20.o \
+ intr_t20.o \
+ cdma_t20.o \
+ 3dctx_t20.o \
+ debug_t20.o
+
+obj-$(CONFIG_TEGRA_GRHOST) += nvhost-t20.o
diff --git a/drivers/video/tegra/host/t20/cdma_t20.c b/drivers/video/tegra/host/t20/cdma_t20.c
new file mode 100644
index 000000000000..77f514eb4e01
--- /dev/null
+++ b/drivers/video/tegra/host/t20/cdma_t20.c
@@ -0,0 +1,243 @@
+/*
+ * drivers/video/tegra/host/t20/cdma_t20.c
+ *
+ * Tegra Graphics Host Command DMA
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "../nvhost_cdma.h"
+#include "../dev.h"
+
+#include "hardware_t20.h"
+
+/*
+ * push_buffer
+ *
+ * The push buffer is a circular array of words to be fetched by command DMA.
+ * Note that it works slightly differently to the sync queue; fence == cur
+ * means that the push buffer is full, not empty.
+ */
+
+
+/**
+ * Reset to empty push buffer
+ */
+static void t20_push_buffer_reset(struct push_buffer *pb)
+{
+ pb->fence = PUSH_BUFFER_SIZE - 8;
+ pb->cur = 0;
+}
+
+/**
+ * Init push buffer resources
+ */
+static int t20_push_buffer_init(struct push_buffer *pb)
+{
+ struct nvhost_cdma *cdma = pb_to_cdma(pb);
+ struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
+ pb->mem = NULL;
+ pb->mapped = NULL;
+ pb->phys = 0;
+
+ BUG_ON(!cdma_pb_op(cdma).reset);
+ cdma_pb_op(cdma).reset(pb);
+
+ /* allocate and map pushbuffer memory */
+ pb->mem = nvmap_alloc(nvmap, PUSH_BUFFER_SIZE + 4, 32,
+ NVMAP_HANDLE_WRITE_COMBINE);
+ if (IS_ERR_OR_NULL(pb->mem)) {
+ pb->mem = NULL;
+ goto fail;
+ }
+ pb->mapped = nvmap_mmap(pb->mem);
+ if (pb->mapped == NULL)
+ goto fail;
+
+ /* pin pushbuffer and get physical address */
+ pb->phys = nvmap_pin(nvmap, pb->mem);
+ if (pb->phys >= 0xfffff000) {
+ pb->phys = 0;
+ goto fail;
+ }
+
+ /* put the restart at the end of pushbuffer memory */
+ *(pb->mapped + (PUSH_BUFFER_SIZE >> 2)) = nvhost_opcode_restart(pb->phys);
+
+ return 0;
+
+fail:
+ cdma_pb_op(cdma).destroy(pb);
+ return -ENOMEM;
+}
+
+/**
+ * Clean up push buffer resources
+ */
+static void t20_push_buffer_destroy(struct push_buffer *pb)
+{
+ struct nvhost_cdma *cdma = pb_to_cdma(pb);
+ struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
+ if (pb->mapped)
+ nvmap_munmap(pb->mem, pb->mapped);
+
+ if (pb->phys != 0)
+ nvmap_unpin(nvmap, pb->mem);
+
+ if (pb->mem)
+ nvmap_free(nvmap, pb->mem);
+
+ pb->mem = NULL;
+ pb->mapped = NULL;
+ pb->phys = 0;
+}
+
+/**
+ * Push two words to the push buffer
+ * Caller must ensure push buffer is not full
+ */
+static void t20_push_buffer_push_to(struct push_buffer *pb, u32 op1, u32 op2)
+{
+ u32 cur = pb->cur;
+ u32 *p = (u32*)((u32)pb->mapped + cur);
+ BUG_ON(cur == pb->fence);
+ *(p++) = op1;
+ *(p++) = op2;
+ pb->cur = (cur + 8) & (PUSH_BUFFER_SIZE - 1);
+ /* printk("push_to_push_buffer: op1=%08x; op2=%08x; cur=%x\n", op1, op2, pb->cur); */
+}
+
+/**
+ * Pop a number of two word slots from the push buffer
+ * Caller must ensure push buffer is not empty
+ */
+static void t20_push_buffer_pop_from(struct push_buffer *pb, unsigned int slots)
+{
+ pb->fence = (pb->fence + slots * 8) & (PUSH_BUFFER_SIZE - 1);
+}
+
+/**
+ * Return the number of two word slots free in the push buffer
+ */
+static u32 t20_push_buffer_space(struct push_buffer *pb)
+{
+ return ((pb->fence - pb->cur) & (PUSH_BUFFER_SIZE - 1)) / 8;
+}
+
+static u32 t20_push_buffer_putptr(struct push_buffer *pb)
+{
+ return pb->phys + pb->cur;
+}
+
+
+/**
+ * Start channel DMA
+ */
+static void t20_cdma_start(struct nvhost_cdma *cdma)
+{
+ void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
+
+ if (cdma->running)
+ return;
+
+ BUG_ON(!cdma_pb_op(cdma).putptr);
+
+ cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+
+ writel(nvhost_channel_dmactrl(true, false, false),
+ chan_regs + HOST1X_CHANNEL_DMACTRL);
+
+ /* set base, put, end pointer (all of memory) */
+ writel(0, chan_regs + HOST1X_CHANNEL_DMASTART);
+ writel(cdma->last_put, chan_regs + HOST1X_CHANNEL_DMAPUT);
+ writel(0xFFFFFFFF, chan_regs + HOST1X_CHANNEL_DMAEND);
+
+ /* reset GET */
+ writel(nvhost_channel_dmactrl(true, true, true),
+ chan_regs + HOST1X_CHANNEL_DMACTRL);
+
+ /* start the command DMA */
+ writel(nvhost_channel_dmactrl(false, false, false),
+ chan_regs + HOST1X_CHANNEL_DMACTRL);
+
+ cdma->running = true;
+}
+
+/**
+ * Kick channel DMA into action by writing its PUT offset (if it has changed)
+ */
+static void t20_cdma_kick(struct nvhost_cdma *cdma)
+{
+ u32 put;
+ BUG_ON(!cdma_pb_op(cdma).putptr);
+
+ put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
+
+ if (put != cdma->last_put) {
+ void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
+ wmb();
+ writel(put, chan_regs + HOST1X_CHANNEL_DMAPUT);
+ cdma->last_put = put;
+ }
+}
+
+static void t20_cdma_stop(struct nvhost_cdma *cdma)
+{
+ void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
+
+ mutex_lock(&cdma->lock);
+ if (cdma->running) {
+ nvhost_cdma_wait(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY);
+ writel(nvhost_channel_dmactrl(true, false, false),
+ chan_regs + HOST1X_CHANNEL_DMACTRL);
+ cdma->running = false;
+ }
+ mutex_unlock(&cdma->lock);
+}
+
+/**
+ * Retrieve the op pair at a slot offset from a DMA address
+ */
+void t20_cdma_peek(struct nvhost_cdma *cdma,
+ u32 dmaget, int slot, u32 *out)
+{
+ u32 offset = dmaget - cdma->push_buffer.phys;
+ u32 *p = cdma->push_buffer.mapped;
+
+ offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
+ out[0] = p[offset];
+ out[1] = p[offset + 1];
+}
+
+int nvhost_init_t20_cdma_support(struct nvhost_master *host)
+{
+ host->op.cdma.start = t20_cdma_start;
+ host->op.cdma.stop = t20_cdma_stop;
+ host->op.cdma.kick = t20_cdma_kick;
+
+ host->sync_queue_size = NVHOST_SYNC_QUEUE_SIZE;
+
+ host->op.push_buffer.reset = t20_push_buffer_reset;
+ host->op.push_buffer.init = t20_push_buffer_init;
+ host->op.push_buffer.destroy = t20_push_buffer_destroy;
+ host->op.push_buffer.push_to = t20_push_buffer_push_to;
+ host->op.push_buffer.pop_from = t20_push_buffer_pop_from;
+ host->op.push_buffer.space = t20_push_buffer_space;
+ host->op.push_buffer.putptr = t20_push_buffer_putptr;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/t20/channel_t20.c b/drivers/video/tegra/host/t20/channel_t20.c
new file mode 100644
index 000000000000..68cffd71f7fd
--- /dev/null
+++ b/drivers/video/tegra/host/t20/channel_t20.c
@@ -0,0 +1,367 @@
+/*
+ * drivers/video/tegra/host/t20/channel_t20.c
+ *
+ * Tegra Graphics Host Channel
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "../nvhost_channel.h"
+#include "../dev.h"
+#include "../nvhost_hwctx.h"
+#include <trace/events/nvhost.h>
+
+#include "hardware_t20.h"
+#include "syncpt_t20.h"
+
+#define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
+#define NVHOST_CHANNEL_BASE 0
+
+#define NVMODMUTEX_2D_FULL (1)
+#define NVMODMUTEX_2D_SIMPLE (2)
+#define NVMODMUTEX_2D_SB_A (3)
+#define NVMODMUTEX_2D_SB_B (4)
+#define NVMODMUTEX_3D (5)
+#define NVMODMUTEX_DISPLAYA (6)
+#define NVMODMUTEX_DISPLAYB (7)
+#define NVMODMUTEX_VI (8)
+#define NVMODMUTEX_DSI (9)
+
+static void power_2d(struct nvhost_module *mod, enum nvhost_power_action action);
+static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action);
+static void power_mpe(struct nvhost_module *mod, enum nvhost_power_action action);
+
+
+
+static const struct nvhost_channeldesc channelmap[] = {
+{
+ /* channel 0 */
+ .name = "display",
+ .syncpts = BIT(NVSYNCPT_DISP0) | BIT(NVSYNCPT_DISP1) |
+ BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
+ .modulemutexes = BIT(NVMODMUTEX_DISPLAYA) | BIT(NVMODMUTEX_DISPLAYB),
+},
+{
+ /* channel 1 */
+ .name = "gr3d",
+ .syncpts = BIT(NVSYNCPT_3D),
+ .waitbases = BIT(NVWAITBASE_3D),
+ .modulemutexes = BIT(NVMODMUTEX_3D),
+ .class = NV_GRAPHICS_3D_CLASS_ID,
+ .power = power_3d,
+},
+{
+ /* channel 2 */
+ .name = "gr2d",
+ .syncpts = BIT(NVSYNCPT_2D_0) | BIT(NVSYNCPT_2D_1),
+ .waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
+ .modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
+ BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
+ .power = power_2d,
+},
+{
+ /* channel 3 */
+ .name = "isp",
+ .syncpts = 0,
+},
+{
+ /* channel 4 */
+ .name = "vi",
+ .syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
+ BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) |
+ BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
+ BIT(NVSYNCPT_VI_ISP_4),
+ .modulemutexes = BIT(NVMODMUTEX_VI),
+ .exclusive = true,
+},
+{
+ /* channel 5 */
+ .name = "mpe",
+ .syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
+ BIT(NVSYNCPT_MPE_WR_SAFE),
+ .waitbases = BIT(NVWAITBASE_MPE),
+ .class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
+ .power = power_mpe,
+ .exclusive = true,
+ .keepalive = true,
+},
+{
+ /* channel 6 */
+ .name = "dsi",
+ .syncpts = BIT(NVSYNCPT_DSI),
+ .modulemutexes = BIT(NVMODMUTEX_DSI),
+}};
+
+static inline void __iomem *t20_channel_aperture(void __iomem *p, int ndx)
+{
+ ndx += NVHOST_CHANNEL_BASE;
+ p += NV_HOST1X_CHANNEL0_BASE;
+ p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
+ return p;
+}
+
+
+int t20_nvhost_3dctx_handler_init(struct nvhost_hwctx_handler *h);
+int t20_nvhost_mpectx_handler_init(struct nvhost_hwctx_handler *h);
+
+static inline int t20_nvhost_hwctx_handler_init(
+ struct nvhost_hwctx_handler *h,
+ const char *module)
+{
+ if (strcmp(module, "gr3d") == 0)
+ return t20_nvhost_3dctx_handler_init(h);
+ else if (strcmp(module, "mpe") == 0)
+ return t20_nvhost_mpectx_handler_init(h);
+
+ return 0;
+}
+
+
+static int t20_channel_init(struct nvhost_channel *ch,
+ struct nvhost_master *dev, int index)
+{
+ ch->dev = dev;
+ ch->desc = channelmap + index;
+ mutex_init(&ch->reflock);
+ mutex_init(&ch->submitlock);
+
+ ch->aperture = t20_channel_aperture(dev->aperture, index);
+
+ return t20_nvhost_hwctx_handler_init(&ch->ctxhandler, ch->desc->name);
+}
+
+
+
+static int t20_channel_submit(struct nvhost_channel *channel,
+ struct nvhost_hwctx *hwctx,
+ struct nvmap_client *user_nvmap,
+ u32 *gather,
+ u32 *gather_end,
+ struct nvhost_waitchk *waitchk,
+ struct nvhost_waitchk *waitchk_end,
+ u32 waitchk_mask,
+ struct nvmap_handle **unpins,
+ int nr_unpins,
+ u32 syncpt_id,
+ u32 syncpt_incrs,
+ u32 *syncpt_value,
+ bool null_kickoff)
+{
+ struct nvhost_hwctx *hwctx_to_save = NULL;
+ struct nvhost_syncpt *sp = &channel->dev->syncpt;
+ u32 user_syncpt_incrs = syncpt_incrs;
+ bool need_restore = false;
+ u32 syncval;
+ int err;
+
+ /* keep module powered */
+ nvhost_module_busy(&channel->mod);
+
+ /* get submit lock */
+ err = mutex_lock_interruptible(&channel->submitlock);
+ if (err) {
+ nvhost_module_idle(&channel->mod);
+ return err;
+ }
+
+ /* remove stale waits */
+ if (waitchk != waitchk_end) {
+ err = nvhost_syncpt_wait_check(sp,
+ user_nvmap,
+ waitchk_mask,
+ waitchk, waitchk_end);
+ if (err) {
+ dev_warn(&channel->dev->pdev->dev,
+ "nvhost_syncpt_wait_check failed: %d\n", err);
+ mutex_unlock(&channel->submitlock);
+ nvhost_module_idle(&channel->mod);
+ return err;
+ }
+ }
+
+ /* context switch */
+ if (channel->cur_ctx != hwctx) {
+ trace_nvhost_channel_context_switch(channel->desc->name,
+ channel->cur_ctx, hwctx);
+ hwctx_to_save = channel->cur_ctx;
+ if (hwctx_to_save) {
+ syncpt_incrs += hwctx_to_save->save_incrs;
+ hwctx_to_save->valid = true;
+ channel->ctxhandler.get(hwctx_to_save);
+ }
+ channel->cur_ctx = hwctx;
+ if (channel->cur_ctx && channel->cur_ctx->valid) {
+ need_restore = true;
+ syncpt_incrs += channel->cur_ctx->restore_incrs;
+ }
+ }
+
+ /* get absolute sync value */
+ if (BIT(syncpt_id) & sp->client_managed)
+ syncval = nvhost_syncpt_set_max(sp,
+ syncpt_id, syncpt_incrs);
+ else
+ syncval = nvhost_syncpt_incr_max(sp,
+ syncpt_id, syncpt_incrs);
+
+ /* begin a CDMA submit */
+ nvhost_cdma_begin(&channel->cdma);
+
+ /* push save buffer (pre-gather setup depends on unit) */
+ if (hwctx_to_save)
+ channel->ctxhandler.save_push(&channel->cdma, hwctx_to_save);
+
+ /* gather restore buffer */
+ if (need_restore)
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_gather(channel->cur_ctx->restore_size),
+ channel->cur_ctx->restore_phys);
+
+ /* add a setclass for modules that require it (unless ctxsw added it) */
+ if (!hwctx_to_save && !need_restore && channel->desc->class)
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_setclass(channel->desc->class, 0, 0),
+ NVHOST_OPCODE_NOOP);
+
+ if (null_kickoff) {
+ int incr;
+ u32 op_incr;
+
+ /* TODO ideally we'd also perform host waits here */
+
+ /* push increments that correspond to nulled out commands */
+ op_incr = nvhost_opcode_imm(0, 0x100 | syncpt_id);
+ for (incr = 0; incr < (user_syncpt_incrs >> 1); incr++)
+ nvhost_cdma_push(&channel->cdma, op_incr, op_incr);
+ if (user_syncpt_incrs & 1)
+ nvhost_cdma_push(&channel->cdma,
+ op_incr, NVHOST_OPCODE_NOOP);
+
+ /* for 3d, waitbase needs to be incremented after each submit */
+ if (channel->desc->class == NV_GRAPHICS_3D_CLASS_ID)
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_setclass(
+ NV_HOST1X_CLASS_ID,
+ NV_CLASS_HOST_INCR_SYNCPT_BASE,
+ 1),
+ nvhost_class_host_incr_syncpt_base(
+ NVWAITBASE_3D,
+ user_syncpt_incrs));
+ }
+ else {
+ /* push user gathers */
+ for ( ; gather != gather_end; gather += 2)
+ nvhost_cdma_push(&channel->cdma,
+ nvhost_opcode_gather(gather[0]),
+ gather[1]);
+ }
+
+ /* end CDMA submit & stash pinned hMems into sync queue */
+ nvhost_cdma_end(&channel->cdma, user_nvmap,
+ syncpt_id, syncval, unpins, nr_unpins);
+
+ /*
+ * schedule a context save interrupt (to drain the host FIFO
+ * if necessary, and to release the restore buffer)
+ */
+ if (hwctx_to_save)
+ nvhost_intr_add_action(&channel->dev->intr, syncpt_id,
+ syncval - syncpt_incrs + hwctx_to_save->save_thresh,
+ NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
+
+ /* schedule a submit complete interrupt */
+ nvhost_intr_add_action(&channel->dev->intr, syncpt_id, syncval,
+ NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel, NULL);
+
+ mutex_unlock(&channel->submitlock);
+
+ *syncpt_value = syncval;
+ return 0;
+}
+
+static void power_2d(struct nvhost_module *mod, enum nvhost_power_action action)
+{
+ /* TODO: [ahatala 2010-06-17] reimplement EPP hang war */
+ if (action == NVHOST_POWER_ACTION_OFF) {
+ /* TODO: [ahatala 2010-06-17] reset EPP */
+ }
+}
+
+static void power_3d(struct nvhost_module *mod, enum nvhost_power_action action)
+{
+ struct nvhost_channel *ch = container_of(mod, struct nvhost_channel, mod);
+ struct nvhost_hwctx *hwctx_to_save;
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
+ u32 syncpt_incrs, syncpt_val;
+ void *ref;
+
+ if (action != NVHOST_POWER_ACTION_OFF)
+ return;
+
+ mutex_lock(&ch->submitlock);
+ hwctx_to_save = ch->cur_ctx;
+ if (!hwctx_to_save) {
+ mutex_unlock(&ch->submitlock);
+ return;
+ }
+
+ hwctx_to_save->valid = true;
+ ch->ctxhandler.get(hwctx_to_save);
+ ch->cur_ctx = NULL;
+
+ syncpt_incrs = hwctx_to_save->save_incrs;
+ syncpt_val = nvhost_syncpt_incr_max(&ch->dev->syncpt,
+ NVSYNCPT_3D, syncpt_incrs);
+
+ nvhost_cdma_begin(&ch->cdma);
+ ch->ctxhandler.save_push(&ch->cdma, hwctx_to_save);
+ nvhost_cdma_end(&ch->cdma, ch->dev->nvmap, NVSYNCPT_3D, syncpt_val, NULL, 0);
+
+ nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D,
+ syncpt_val - syncpt_incrs + hwctx_to_save->save_thresh,
+ NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save, NULL);
+
+ nvhost_intr_add_action(&ch->dev->intr, NVSYNCPT_3D, syncpt_val,
+ NVHOST_INTR_ACTION_WAKEUP, &wq, &ref);
+ wait_event(wq,
+ nvhost_syncpt_min_cmp(&ch->dev->syncpt,
+ NVSYNCPT_3D, syncpt_val));
+
+ nvhost_intr_put_ref(&ch->dev->intr, ref);
+
+ nvhost_cdma_update(&ch->cdma);
+
+ mutex_unlock(&ch->submitlock);
+}
+
+static void power_mpe(struct nvhost_module *mod, enum nvhost_power_action action)
+{
+}
+
+int nvhost_init_t20_channel_support(struct nvhost_master *host)
+{
+
+ BUILD_BUG_ON(NVHOST_NUMCHANNELS != ARRAY_SIZE(channelmap));
+
+ host->nb_mlocks = NV_HOST1X_SYNC_MLOCK_NUM;
+ host->nb_channels = NVHOST_NUMCHANNELS;
+
+ host->op.channel.init = t20_channel_init;
+ host->op.channel.submit = t20_channel_submit;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/t20/cpuaccess_t20.c b/drivers/video/tegra/host/t20/cpuaccess_t20.c
new file mode 100644
index 000000000000..f6bb76f4165a
--- /dev/null
+++ b/drivers/video/tegra/host/t20/cpuaccess_t20.c
@@ -0,0 +1,55 @@
+/*
+ * drivers/video/tegra/host/cpuaccess_t20.c
+ *
+ * Tegra Graphics Host Cpu Register Access
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "../nvhost_cpuaccess.h"
+#include "../dev.h"
+
+#include "hardware_t20.h"
+
+static int t20_cpuaccess_mutex_try_lock(struct nvhost_cpuaccess *ctx,
+ unsigned int idx)
+{
+ struct nvhost_master *dev = cpuaccess_to_dev(ctx);
+ void __iomem *sync_regs = dev->sync_aperture;
+ /* mlock registers returns 0 when the lock is aquired.
+ * writing 0 clears the lock. */
+ return !!readl(sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
+}
+
+static void t20_cpuaccess_mutex_unlock(struct nvhost_cpuaccess *ctx,
+ unsigned int idx)
+{
+ struct nvhost_master *dev = cpuaccess_to_dev(ctx);
+ void __iomem *sync_regs = dev->sync_aperture;
+
+ writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
+}
+
+int nvhost_init_t20_cpuaccess_support(struct nvhost_master *host)
+{
+ host->nb_modules = NVHOST_MODULE_NUM;
+
+ host->op.cpuaccess.mutex_try_lock = t20_cpuaccess_mutex_try_lock;
+ host->op.cpuaccess.mutex_unlock = t20_cpuaccess_mutex_unlock;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/t20/debug_t20.c b/drivers/video/tegra/host/t20/debug_t20.c
new file mode 100644
index 000000000000..0c77745b8c41
--- /dev/null
+++ b/drivers/video/tegra/host/t20/debug_t20.c
@@ -0,0 +1,308 @@
+/*
+ * drivers/video/tegra/host/t20/debug_t20.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ *
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/io.h>
+
+#include "../dev.h"
+#include "../debug.h"
+#include "../nvhost_cdma.h"
+
+#include "hardware_t20.h"
+
+enum {
+ NVHOST_DBG_STATE_CMD = 0,
+ NVHOST_DBG_STATE_DATA = 1,
+ NVHOST_DBG_STATE_GATHER = 2
+};
+
+static int show_channel_command(struct output *o, u32 val, int *count)
+{
+ unsigned mask;
+ unsigned subop;
+
+ switch (val >> 28) {
+ case 0x0:
+ mask = val & 0x3f;
+ if (mask) {
+ nvhost_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
+ val >> 6 & 0x3ff, val >> 16 & 0xfff, mask);
+ *count = hweight8(mask);
+ return NVHOST_DBG_STATE_DATA;
+ } else {
+ nvhost_debug_output(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff);
+ return NVHOST_DBG_STATE_CMD;
+ }
+
+ case 0x1:
+ nvhost_debug_output(o, "INCR(offset=%03x, [", val >> 16 & 0xfff);
+ *count = val & 0xffff;
+ return NVHOST_DBG_STATE_DATA;
+
+ case 0x2:
+ nvhost_debug_output(o, "NONINCR(offset=%03x, [", val >> 16 & 0xfff);
+ *count = val & 0xffff;
+ return NVHOST_DBG_STATE_DATA;
+
+ case 0x3:
+ mask = val & 0xffff;
+ nvhost_debug_output(o, "MASK(offset=%03x, mask=%03x, [",
+ val >> 16 & 0xfff, mask);
+ *count = hweight16(mask);
+ return NVHOST_DBG_STATE_DATA;
+
+ case 0x4:
+ nvhost_debug_output(o, "IMM(offset=%03x, data=%03x)\n",
+ val >> 16 & 0xfff, val & 0xffff);
+ return NVHOST_DBG_STATE_CMD;
+
+ case 0x5:
+ nvhost_debug_output(o, "RESTART(offset=%08x)\n", val << 4);
+ return NVHOST_DBG_STATE_CMD;
+
+ case 0x6:
+ nvhost_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
+ val >> 16 & 0xfff, val >> 15 & 0x1, val >> 14 & 0x1,
+ val & 0x3fff);
+ *count = val & 0x3fff; // TODO: insert
+ return NVHOST_DBG_STATE_GATHER;
+
+ case 0xe:
+ subop = val >> 24 & 0xf;
+ if (subop == 0)
+ nvhost_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n", val & 0xff);
+ else if (subop == 1)
+ nvhost_debug_output(o, "RELEASE_MLOCK(index=%d)\n", val & 0xff);
+ else
+ nvhost_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val);
+ return NVHOST_DBG_STATE_CMD;
+
+ default:
+ return NVHOST_DBG_STATE_CMD;
+ }
+}
+
+/*
+ * TODO: This uses ioremap_xxx on memory which is deprecated.
+ * Also, it won't work properly with SMMU.
+ */
+static void show_channel_gather(struct output *o, u32 phys_addr,
+ phys_addr_t words);
+
+static void show_channel_word(struct output *o, int *state, int *count,
+ u32 addr, u32 val)
+{
+ switch (*state) {
+ case NVHOST_DBG_STATE_CMD:
+ if (addr)
+ nvhost_debug_output(o, "%08x: %08x:", addr, val);
+ else
+ nvhost_debug_output(o, "%08x:", val);
+
+ *state = show_channel_command(o, val, count);
+ if (*state == NVHOST_DBG_STATE_DATA && *count == 0) {
+ *state = NVHOST_DBG_STATE_CMD;
+ nvhost_debug_output(o, "])\n");
+ }
+ break;
+
+ case NVHOST_DBG_STATE_DATA:
+ (*count)--;
+ nvhost_debug_output(o, "%08x%s", val, *count > 0 ? ", " : "])\n");
+ if (*count == 0)
+ *state = NVHOST_DBG_STATE_CMD;
+ break;
+
+ case NVHOST_DBG_STATE_GATHER:
+ *state = NVHOST_DBG_STATE_CMD;
+ nvhost_debug_output(o, "%08x]):\n", val);
+ show_channel_gather(o, val, *count);
+ break;
+ }
+}
+
+static void show_channel_gather(struct output *o, phys_addr_t phys_addr,
+ u32 words)
+{
+ phys_addr_t map_base = phys_addr & PAGE_MASK;
+ phys_addr_t map_end = (phys_addr + words * 4 + PAGE_SIZE - 1) & PAGE_MASK;
+ phys_addr_t map_size = map_end - map_base;
+ phys_addr_t map_offset = phys_addr - map_base;
+ void *map_addr = ioremap_nocache(map_base, map_size);
+ int state = NVHOST_DBG_STATE_CMD;
+ int count, i;
+
+ if (!map_addr)
+ return;
+ for (i = 0; i < words; i++)
+ show_channel_word(o, &state, &count, phys_addr + i * 4,
+ readl(map_addr + map_offset + i * 4));
+ iounmap(map_addr);
+}
+
+static void show_channel_pair(struct output *o, u32 addr,
+ u32 w0, u32 w1)
+{
+ int state = NVHOST_DBG_STATE_CMD;
+ int count;
+
+ show_channel_word(o, &state, &count, addr, w0);
+ show_channel_word(o, &state, &count, addr, w1);
+}
+
+/**
+ * Retrieve the op pair at a slot offset from a DMA address
+ */
+static void cdma_peek(struct nvhost_cdma *cdma,
+ u32 dmaget, int slot, u32 *out)
+{
+ u32 offset = dmaget - cdma->push_buffer.phys;
+ u32 *p = cdma->push_buffer.mapped;
+
+ offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
+ out[0] = p[offset];
+ out[1] = p[offset + 1];
+}
+
+static void t20_debug_show_channel_cdma(struct nvhost_master *m,
+ struct output *o, int chid)
+{
+ struct nvhost_channel *channel = m->channels + chid;
+ u32 dmaput, dmaget, dmactrl;
+ u32 cbstat, cbread;
+ u32 val, base, baseval;
+ u32 pbw[2];
+
+ dmaput = readl(channel->aperture + HOST1X_CHANNEL_DMAPUT);
+ dmaget = readl(channel->aperture + HOST1X_CHANNEL_DMAGET);
+ dmactrl = readl(channel->aperture + HOST1X_CHANNEL_DMACTRL);
+ cbread = readl(m->aperture + HOST1X_SYNC_CBREAD(chid));
+ cbstat = readl(m->aperture + HOST1X_SYNC_CBSTAT(chid));
+
+ nvhost_debug_output(o, "%d-%s (%d): ", chid,
+ channel->mod.name, atomic_read(&channel->mod.refcount));
+
+ if ((dmactrl & 1) || !channel->cdma.push_buffer.mapped) {
+ nvhost_debug_output(o, "inactive\n\n");
+ return;
+ }
+
+ switch (cbstat) {
+ case 0x00010008:
+ nvhost_debug_output(o, "waiting on syncpt %d val %d\n",
+ cbread >> 24, cbread & 0xffffff);
+ break;
+
+ case 0x00010009:
+ base = (cbread >> 16) & 0xff;
+ val = readl(m->aperture + HOST1X_SYNC_SYNCPT_BASE(base));
+ baseval = val & 0xffff;
+ val = cbread & 0xffff;
+ nvhost_debug_output(o, "waiting on syncpt %d val %d "
+ "(base %d = %d; offset = %d)\n",
+ cbread >> 24, baseval + val,
+ base, baseval, val);
+ break;
+
+ default:
+ nvhost_debug_output(o, "active class %02x, offset %04x, val %08x\n",
+ cbstat >> 16, cbstat & 0xffff, cbread);
+ break;
+ }
+
+ cdma_peek(&channel->cdma, dmaget, -1, pbw);
+ show_channel_pair(o, chid, pbw[0], pbw[1]);
+ nvhost_debug_output(o, "\n");
+}
+
+void t20_debug_show_channel_fifo(struct nvhost_master *m,
+ struct output *o, int chid)
+{
+ u32 val, rd_ptr, wr_ptr, start, end;
+ int state, count;
+
+ val = readl(m->aperture + HOST1X_CHANNEL_FIFOSTAT);
+ if (val & (1 << 10))
+ return;
+
+ writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ writel((1 << 31) | (chid << 16),
+ m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+
+ val = readl(m->aperture + HOST1X_SYNC_CFPEEK_PTRS);
+ rd_ptr = val & 0x1ff;
+ wr_ptr = (val >> 16) & 0x1ff;
+
+ val = readl(m->aperture + HOST1X_SYNC_CF_SETUP(chid));
+ start = val & 0x1ff;
+ end = (val >> 16) & 0x1ff;
+
+ state = NVHOST_DBG_STATE_CMD;
+ nvhost_debug_output(o, "%d: fifo:\n", chid);
+
+ do {
+ writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ writel((1 << 31) | (chid << 16) | rd_ptr,
+ m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+ val = readl(m->aperture + HOST1X_SYNC_CFPEEK_READ);
+
+ show_channel_word(o, &state, &count, 0, val);
+
+ if (rd_ptr == end)
+ rd_ptr = start;
+ else
+ rd_ptr++;
+ } while (rd_ptr != wr_ptr);
+
+ if (state == NVHOST_DBG_STATE_DATA)
+ nvhost_debug_output(o, ", ...])\n");
+ nvhost_debug_output(o, "\n");
+
+ writel(0x0, m->aperture + HOST1X_SYNC_CFPEEK_CTRL);
+}
+
+static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
+{
+ u32 __iomem *mlo_regs = m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0;
+ int i;
+
+ nvhost_debug_output(o, "---- mlocks ----\n");
+ for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
+ u32 owner = readl(mlo_regs + i);
+ if (owner & 0x1)
+ nvhost_debug_output(o, "%d: locked by channel %d\n",
+ i, (owner >> 8) & 0xf);
+ else if (owner & 0x2)
+ nvhost_debug_output(o, "%d: locked by cpu\n", i);
+ else
+ nvhost_debug_output(o, "%d: unlocked\n", i);
+ }
+ nvhost_debug_output(o, "\n");
+}
+
+int nvhost_init_t20_debug_support(struct nvhost_master *host)
+{
+ 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;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/nvhost_hardware.h b/drivers/video/tegra/host/t20/hardware_t20.h
index 8fa219595789..f94137cdafe4 100644
--- a/drivers/video/tegra/host/nvhost_hardware.h
+++ b/drivers/video/tegra/host/t20/hardware_t20.h
@@ -1,9 +1,9 @@
/*
- * drivers/video/tegra/host/nvhost_hardware.h
+ * drivers/video/tegra/host/t20/hardware_t20.h
*
* Tegra Graphics Host Register Offsets
*
- * Copyright (c) 2010, NVIDIA Corporation.
+ * Copyright (c) 2010,2011 NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,8 +20,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __NVHOST_HARDWARE_H
-#define __NVHOST_HARDWARE_H
+#ifndef __NVHOST_HARDWARE_T20_H
+#define __NVHOST_HARDWARE_T20_H
#include <linux/types.h>
#include <linux/bitops.h>
@@ -256,5 +256,15 @@ static inline u32 nvhost_mask2(unsigned x, unsigned y)
return 1 | (1 << (y - x));
}
-#endif /* __NVHOST_HARDWARE_H */
+/* Size of the sync queue. If it is too small, we won't be able to queue up
+ * many command buffers. If it is too large, we waste memory. */
+#define NVHOST_SYNC_QUEUE_SIZE 8192
+/* Number of gathers we allow to be queued up per channel. Must be a
+ * power of two. Currently sized such that pushbuffer is 4KB (512*8B). */
+#define NVHOST_GATHER_QUEUE_SIZE 512
+
+/* 8 bytes per slot. (This number does not include the final RESTART.) */
+#define PUSH_BUFFER_SIZE (NVHOST_GATHER_QUEUE_SIZE * 8)
+
+#endif /* __NVHOST_HARDWARE_T20_H */
diff --git a/drivers/video/tegra/host/t20/intr_t20.c b/drivers/video/tegra/host/t20/intr_t20.c
new file mode 100644
index 000000000000..94bdae4bf392
--- /dev/null
+++ b/drivers/video/tegra/host/t20/intr_t20.c
@@ -0,0 +1,201 @@
+/*
+ * drivers/video/tegra/host/t20/intr_t20.c
+ *
+ * Tegra Graphics Host Interrupt Management
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include "../nvhost_intr.h"
+#include "../dev.h"
+
+#include "hardware_t20.h"
+
+
+/*** HW host sync management ***/
+
+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;
+ /* disable the ip_busy_timeout. this prevents write drops, etc.
+ * there's no real way to recover from a hung client anyway.
+ */
+ writel(0, sync_regs + HOST1X_SYNC_IP_BUSY_TIMEOUT);
+
+ /* increase the auto-ack timout to the maximum value. 2d will hang
+ * otherwise on ap20.
+ */
+ writel(0xff, sync_regs + HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
+}
+
+static void t20_intr_set_host_clocks_per_usec(struct nvhost_intr *intr, u32 cpm)
+{
+ struct nvhost_master *dev = intr_to_dev(intr);
+ void __iomem *sync_regs = dev->sync_aperture;
+ /* write microsecond clock register */
+ writel(cpm, sync_regs + HOST1X_SYNC_USEC_CLK);
+}
+
+static void t20_intr_set_syncpt_threshold(struct nvhost_intr *intr, u32 id, u32 thresh)
+{
+ struct nvhost_master *dev = intr_to_dev(intr);
+ void __iomem *sync_regs = dev->sync_aperture;
+ thresh &= 0xffff;
+ writel(thresh, sync_regs + (HOST1X_SYNC_SYNCPT_INT_THRESH_0 + id * 4));
+}
+
+static void t20_intr_enable_syncpt_intr(struct nvhost_intr *intr, u32 id)
+{
+ struct nvhost_master *dev = intr_to_dev(intr);
+ void __iomem *sync_regs = dev->sync_aperture;
+ writel(BIT(id), sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0);
+}
+
+static void t20_intr_disable_all_syncpt_intrs(struct nvhost_intr *intr)
+{
+ struct nvhost_master *dev = intr_to_dev(intr);
+ void __iomem *sync_regs = dev->sync_aperture;
+ /* disable interrupts for both cpu's */
+ writel(0, sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
+
+ /* clear status for both cpu's */
+ writel(0xfffffffful, sync_regs +
+ HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
+ writel(0xfffffffful, sync_regs +
+ HOST1X_SYNC_SYNCPT_THRESH_CPU1_INT_STATUS);
+}
+
+/**
+ * Sync point threshold interrupt service function
+ * Handles sync point threshold triggers, in interrupt context
+ */
+irqreturn_t t20_intr_syncpt_thresh_isr(int irq, void *dev_id)
+{
+ struct nvhost_intr_syncpt *syncpt = dev_id;
+ unsigned int id = syncpt->id;
+ struct nvhost_intr *intr = intr_syncpt_to_intr(syncpt);
+
+ void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
+
+ writel(BIT(id),
+ sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
+ writel(BIT(id),
+ sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
+
+ return IRQ_WAKE_THREAD;
+}
+
+/**
+ * Host general interrupt service function
+ * Handles read / write failures
+ */
+static irqreturn_t t20_intr_host1x_isr(int irq, void *dev_id)
+{
+ struct nvhost_intr *intr = dev_id;
+ void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
+ u32 stat;
+ u32 ext_stat;
+ u32 addr;
+
+ stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS);
+ ext_stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
+
+ if (nvhost_sync_hintstatus_ext_ip_read_int(ext_stat)) {
+ addr = readl(sync_regs + HOST1X_SYNC_IP_READ_TIMEOUT_ADDR);
+ pr_err("Host read timeout at address %x\n", addr);
+ }
+
+ if (nvhost_sync_hintstatus_ext_ip_write_int(ext_stat)) {
+ addr = readl(sync_regs + HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR);
+ pr_err("Host write timeout at address %x\n", addr);
+ }
+
+ writel(ext_stat, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
+ writel(stat, sync_regs + HOST1X_SYNC_HINTSTATUS);
+
+ return IRQ_HANDLED;
+}
+static int t20_intr_request_host_general_irq(struct nvhost_intr *intr)
+{
+ void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
+ int err;
+
+ if (intr->host_general_irq_requested)
+ return 0;
+
+ /* master disable for general (not syncpt) host interrupts */
+ writel(0, sync_regs + HOST1X_SYNC_INTMASK);
+
+ /* clear status & extstatus */
+ writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
+ writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS);
+
+ err = request_irq(intr->host_general_irq, t20_intr_host1x_isr, 0,
+ "host_status", intr);
+ if (err)
+ return err;
+
+ /* enable extra interrupt sources IP_READ_INT and IP_WRITE_INT */
+ writel(BIT(30) | BIT(31), sync_regs + HOST1X_SYNC_HINTMASK_EXT);
+
+ /* enable extra interrupt sources */
+ writel(BIT(31), sync_regs + HOST1X_SYNC_HINTMASK);
+
+ /* enable host module interrupt to CPU0 */
+ writel(BIT(0), sync_regs + HOST1X_SYNC_INTC0MASK);
+
+ /* master enable for general (not syncpt) host interrupts */
+ writel(BIT(0), sync_regs + HOST1X_SYNC_INTMASK);
+
+ intr->host_general_irq_requested = true;
+
+ return err;
+}
+
+static void t20_intr_free_host_general_irq(struct nvhost_intr *intr)
+{
+ if (intr->host_general_irq_requested) {
+ void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
+
+ /* master disable for general (not syncpt) host interrupts */
+ writel(0, sync_regs + HOST1X_SYNC_INTMASK);
+
+ free_irq(intr->host_general_irq, intr);
+ intr->host_general_irq_requested = false;
+ }
+}
+
+int nvhost_init_t20_intr_support(struct nvhost_master *host)
+{
+ 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;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/t20/syncpt_t20.c b/drivers/video/tegra/host/t20/syncpt_t20.c
new file mode 100644
index 000000000000..07fdb029e742
--- /dev/null
+++ b/drivers/video/tegra/host/t20/syncpt_t20.c
@@ -0,0 +1,214 @@
+/*
+ * drivers/video/tegra/host/t20/syncpt_t20.c
+ *
+ * Tegra Graphics Host Syncpoints for T20
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "../nvhost_syncpt.h"
+#include "../dev.h"
+
+#include "syncpt_t20.h"
+#include "hardware_t20.h"
+
+/**
+ * Write the current syncpoint value back to hw.
+ */
+static void t20_syncpt_reset(struct nvhost_syncpt *sp, u32 id)
+{
+ struct nvhost_master *dev = syncpt_to_dev(sp);
+ int min;
+ smp_rmb();
+ min = atomic_read(&sp->min_val[id]);
+ writel(min, dev->sync_aperture + (HOST1X_SYNC_SYNCPT_0 + id * 4));
+}
+
+/**
+ * Write the current waitbase value back to hw.
+ */
+static void t20_syncpt_reset_wait_base(struct nvhost_syncpt *sp, u32 id)
+{
+ struct nvhost_master *dev = syncpt_to_dev(sp);
+ writel(sp->base_val[id],
+ dev->sync_aperture + (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
+}
+
+/**
+ * Read waitbase value from hw.
+ */
+static void t20_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
+{
+ struct nvhost_master *dev = syncpt_to_dev(sp);
+ sp->base_val[id] = readl(dev->sync_aperture +
+ (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
+}
+
+/**
+ * Updates the last value read from hardware.
+ * (was nvhost_syncpt_update_min)
+ */
+static u32 t20_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
+{
+ struct nvhost_master *dev = syncpt_to_dev(sp);
+ void __iomem *sync_regs = dev->sync_aperture;
+ u32 old, live;
+
+ do {
+ smp_rmb();
+ old = (u32)atomic_read(&sp->min_val[id]);
+ live = readl(sync_regs + (HOST1X_SYNC_SYNCPT_0 + id * 4));
+ } while ((u32)atomic_cmpxchg(&sp->min_val[id], old, live) != old);
+
+ BUG_ON(!nvhost_syncpt_check_max(sp, id, live));
+
+ return live;
+}
+
+/**
+ * Write a cpu syncpoint increment to the hardware, without touching
+ * the cache. Caller is responsible for host being powered.
+ */
+static void t20_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
+{
+ struct nvhost_master *dev = syncpt_to_dev(sp);
+ BUG_ON(!nvhost_module_powered(&dev->mod));
+ BUG_ON(!client_managed(id) && nvhost_syncpt_min_eq_max(sp, id));
+ writel(BIT(id), dev->sync_aperture + HOST1X_SYNC_SYNCPT_CPU_INCR);
+ wmb();
+}
+
+/* returns true, if a <= b < c using wrapping comparison */
+static inline bool nvhost_syncpt_is_between(u32 a, u32 b, u32 c)
+{
+ return b-a < c-a;
+}
+
+/* returns true, if syncpt >= threshold (mod 1 << 32) */
+static bool nvhost_syncpt_wrapping_comparison(u32 syncpt, u32 threshold)
+{
+ return nvhost_syncpt_is_between(threshold, syncpt,
+ (1UL<<31UL)+threshold);
+}
+
+/* check for old WAITs to be removed (avoiding a wrap) */
+static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
+ struct nvmap_client *nvmap,
+ u32 waitchk_mask,
+ struct nvhost_waitchk *wait,
+ struct nvhost_waitchk *waitend)
+{
+ u32 idx;
+ int err = 0;
+
+ /* get current syncpt values */
+ for (idx = 0; idx < NV_HOST1X_SYNCPT_NB_PTS; idx++) {
+ if (BIT(idx) & waitchk_mask)
+ nvhost_syncpt_update_min(sp, idx);
+ }
+
+ BUG_ON(!wait && !waitend);
+
+ /* compare syncpt vs wait threshold */
+ while (wait != waitend) {
+ u32 syncpt, override;
+
+ BUG_ON(wait->syncpt_id > NV_HOST1X_SYNCPT_NB_PTS);
+
+ syncpt = atomic_read(&sp->min_val[wait->syncpt_id]);
+ if (nvhost_syncpt_wrapping_comparison(syncpt, wait->thresh)) {
+ /*
+ * NULL an already satisfied WAIT_SYNCPT host method,
+ * by patching its args in the command stream. The
+ * method data is changed to reference a reserved
+ * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
+ * syncpt with a matching threshold value of 0, so
+ * is guaranteed to be popped by the host HW.
+ */
+ dev_dbg(&syncpt_to_dev(sp)->pdev->dev,
+ "drop WAIT id %d (%s) thresh 0x%x, syncpt 0x%x\n",
+ wait->syncpt_id,
+ nvhost_syncpt_name(wait->syncpt_id),
+ wait->thresh, syncpt);
+
+ /* patch the wait */
+ override = nvhost_class_host_wait_syncpt(
+ NVSYNCPT_GRAPHICS_HOST, 0);
+ err = nvmap_patch_word(nvmap,
+ (struct nvmap_handle *)wait->mem,
+ wait->offset, override);
+ if (err)
+ break;
+ }
+ wait++;
+ }
+ return err;
+}
+
+
+static const char *s_syncpt_names[32] = {
+ "gfx_host", "", "", "", "", "", "", "", "", "", "",
+ "csi_vi_0", "csi_vi_1", "vi_isp_0", "vi_isp_1", "vi_isp_2", "vi_isp_3", "vi_isp_4",
+ "2d_0", "2d_1",
+ "", "",
+ "3d", "mpe", "disp0", "disp1", "vblank0", "vblank1", "mpe_ebm_eof", "mpe_wr_safe",
+ "2d_tinyblt", "dsi"
+};
+
+static const char *t20_syncpt_name(struct nvhost_syncpt *s, u32 id)
+{
+ BUG_ON(id > ARRAY_SIZE(s_syncpt_names));
+ return s_syncpt_names[id];
+}
+
+static void t20_syncpt_debug(struct nvhost_syncpt *sp)
+{
+ u32 i;
+ for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
+ u32 max = nvhost_syncpt_read_max(sp, i);
+ if (!max)
+ continue;
+ dev_info(&syncpt_to_dev(sp)->pdev->dev,
+ "id %d (%s) min %d max %d\n",
+ i, syncpt_op(sp).name(sp, i),
+ nvhost_syncpt_update_min(sp, i), max);
+
+ }
+}
+
+int nvhost_init_t20_syncpt_support(struct nvhost_master *host)
+{
+
+ 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->syncpt.nb_pts = NV_HOST1X_SYNCPT_NB_PTS;
+ host->syncpt.nb_bases = NV_HOST1X_SYNCPT_NB_BASES;
+ host->syncpt.client_managed = NVSYNCPTS_CLIENT_MANAGED;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/host/t20/syncpt_t20.h b/drivers/video/tegra/host/t20/syncpt_t20.h
new file mode 100644
index 000000000000..5c7c04cad91e
--- /dev/null
+++ b/drivers/video/tegra/host/t20/syncpt_t20.h
@@ -0,0 +1,68 @@
+/*
+ * drivers/video/tegra/host/t20/syncpt_t20.h
+ *
+ * Tegra Graphics Host Syncpoints for T20
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NVHOST_SYNCPT_T20_H
+#define __NVHOST_SYNCPT_T20_H
+
+#define NVSYNCPT_CSI_VI_0 (11)
+#define NVSYNCPT_CSI_VI_1 (12)
+#define NVSYNCPT_VI_ISP_0 (13)
+#define NVSYNCPT_VI_ISP_1 (14)
+#define NVSYNCPT_VI_ISP_2 (15)
+#define NVSYNCPT_VI_ISP_3 (16)
+#define NVSYNCPT_VI_ISP_4 (17)
+#define NVSYNCPT_2D_0 (18)
+#define NVSYNCPT_2D_1 (19)
+#define NVSYNCPT_3D (22)
+#define NVSYNCPT_MPE (23)
+#define NVSYNCPT_DISP0 (24)
+#define NVSYNCPT_DISP1 (25)
+#define NVSYNCPT_VBLANK0 (26)
+#define NVSYNCPT_VBLANK1 (27)
+#define NVSYNCPT_MPE_EBM_EOF (28)
+#define NVSYNCPT_MPE_WR_SAFE (29)
+#define NVSYNCPT_DSI (31)
+
+
+/*#define NVSYNCPT_2D_CHANNEL2_0 (20) */
+/*#define NVSYNCPT_2D_CHANNEL2_1 (21) */
+/*#define NVSYNCPT_2D_TINYBLT_WAR (30)*/
+/*#define NVSYNCPT_2D_TINYBLT_RESTORE_CLASS_ID (30)*/
+
+/* sync points that are wholly managed by the client */
+#define NVSYNCPTS_CLIENT_MANAGED ( \
+ BIT(NVSYNCPT_DISP0) | BIT(NVSYNCPT_DISP1) | BIT(NVSYNCPT_DSI) | \
+ BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) | \
+ BIT(NVSYNCPT_VI_ISP_1) | BIT(NVSYNCPT_VI_ISP_2) | \
+ BIT(NVSYNCPT_VI_ISP_3) | BIT(NVSYNCPT_VI_ISP_4) | \
+ BIT(NVSYNCPT_MPE_EBM_EOF) | BIT(NVSYNCPT_MPE_WR_SAFE) | \
+ BIT(NVSYNCPT_2D_1))
+
+
+#define NVWAITBASE_2D_0 (1)
+#define NVWAITBASE_2D_1 (2)
+#define NVWAITBASE_3D (3)
+#define NVWAITBASE_MPE (4)
+
+int nvhost_t20_init_syncpt(struct nvhost_master *host);
+
+#endif /* __NVHOST_SYNCPT_T20_H */
diff --git a/drivers/video/tegra/host/t20/t20.c b/drivers/video/tegra/host/t20/t20.c
new file mode 100644
index 000000000000..c846ce7cf289
--- /dev/null
+++ b/drivers/video/tegra/host/t20/t20.c
@@ -0,0 +1,51 @@
+/*
+ * drivers/video/tegra/host/t20/t20.c
+ *
+ * Tegra Graphics Init for T20 Architecture Chips
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "../dev.h"
+
+#include "t20.h"
+
+int nvhost_init_t20_support(struct nvhost_master *host)
+{
+ int err;
+
+ /* don't worry about cleaning up on failure... "remove" does it. */
+ err = nvhost_init_t20_channel_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_cdma_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_debug_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_syncpt_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_intr_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_cpuaccess_support(host);
+ if (err)
+ return err;
+ return 0;
+}
diff --git a/drivers/video/tegra/host/t20/t20.h b/drivers/video/tegra/host/t20/t20.h
new file mode 100644
index 000000000000..8a8426c740d1
--- /dev/null
+++ b/drivers/video/tegra/host/t20/t20.h
@@ -0,0 +1,32 @@
+/*
+ * drivers/video/tegra/host/t20/t20.h
+ *
+ * Tegra Graphics Chip support for T20
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _NVHOST_T20_H_
+#define _NVHOST_T20_H_
+
+int nvhost_init_t20_channel_support(struct nvhost_master *);
+int nvhost_init_t20_cdma_support(struct nvhost_master *);
+int nvhost_init_t20_debug_support(struct nvhost_master *);
+int nvhost_init_t20_syncpt_support(struct nvhost_master *);
+int nvhost_init_t20_intr_support(struct nvhost_master *);
+int nvhost_init_t20_cpuaccess_support(struct nvhost_master *);
+
+#endif /* _NVHOST_T20_H_ */
diff --git a/drivers/video/tegra/host/t30/Makefile b/drivers/video/tegra/host/t30/Makefile
new file mode 100644
index 000000000000..f394706ac134
--- /dev/null
+++ b/drivers/video/tegra/host/t30/Makefile
@@ -0,0 +1,4 @@
+nvhost-t30-objs = \
+ t30.o
+
+obj-$(CONFIG_TEGRA_GRHOST) += nvhost-t30.o
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
new file mode 100644
index 000000000000..5185541f029a
--- /dev/null
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -0,0 +1,54 @@
+/*
+ * drivers/video/tegra/host/t30/t30.c
+ *
+ * Tegra Graphics Init for T30 Architecture Chips
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "../dev.h"
+
+/* t30 uses t20 entry points */
+#include "../t20/t20.h"
+
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+int nvhost_init_t30_support(struct nvhost_master *host)
+{
+ int err;
+
+ /* don't worry about cleaning up on failure... "remove" does it. */
+ err = nvhost_init_t20_channel_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_cdma_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_debug_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_syncpt_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_intr_support(host);
+ if (err)
+ return err;
+ err = nvhost_init_t20_cpuaccess_support(host);
+ if (err)
+ return err;
+ return 0;
+}
+#endif