summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r--drivers/video/tegra/dc/dc.c32
-rw-r--r--drivers/video/tegra/dc/dc_reg.h4
-rw-r--r--drivers/video/tegra/dc/hdmi.c33
-rw-r--r--drivers/video/tegra/fb.c13
-rw-r--r--drivers/video/tegra/host/debug.c76
-rw-r--r--drivers/video/tegra/host/dev.h1
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c10
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c96
8 files changed, 202 insertions, 63 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 8cf9726645c9..83070a76834e 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -747,6 +747,18 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
DC_DISP_DATA_ENABLE_OPTIONS);
+ val = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY1);
+ if (mode->flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC)
+ val |= PIN1_LVS_OUTPUT;
+ else
+ val &= ~PIN1_LVS_OUTPUT;
+
+ if (mode->flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC)
+ val |= PIN1_LHS_OUTPUT;
+ else
+ val &= ~PIN1_LHS_OUTPUT;
+ tegra_dc_writel(dc, val, DC_COM_PIN_OUTPUT_POLARITY1);
+
/* TODO: MIPI/CRT/HDMI clock cals */
val = DISP_DATA_FORMAT_DF1P1C;
@@ -887,6 +899,23 @@ static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out)
}
+unsigned tegra_dc_get_out_height(struct tegra_dc *dc)
+{
+ if (dc->out)
+ return dc->out->height;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_get_out_height);
+
+unsigned tegra_dc_get_out_width(struct tegra_dc *dc)
+{
+ if (dc->out)
+ return dc->out->width;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_get_out_width);
static irqreturn_t tegra_dc_irq(int irq, void *ptr)
{
@@ -1186,8 +1215,9 @@ static void tegra_dc_reset_worker(struct work_struct *work)
mutex_lock(&dc->lock);
_tegra_dc_disable(dc);
+ msleep(100);
tegra_periph_reset_assert(dc->clk);
- msleep(10);
+ msleep(100);
tegra_periph_reset_deassert(dc->clk);
_tegra_dc_enable(dc);
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
index d94a17b67cef..240d8a48d03e 100644
--- a/drivers/video/tegra/dc/dc_reg.h
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -136,6 +136,10 @@
#define DC_COM_PIN_OUTPUT_SELECT4 0x318
#define DC_COM_PIN_OUTPUT_SELECT5 0x319
#define DC_COM_PIN_OUTPUT_SELECT6 0x31a
+
+#define PIN1_LHS_OUTPUT (1 << 30)
+#define PIN1_LVS_OUTPUT (1 << 28)
+
#define DC_COM_PIN_MISC_CONTROL 0x31b
#define DC_COM_PM0_CONTROL 0x31c
#define DC_COM_PM0_DUTY_CYCLE 0x31d
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index 2b4f46ba1221..24e4fed37b40 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -110,7 +110,7 @@ static const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
.right_margin = 16, /* h_front_porch */
.lower_margin = 9, /* v_front_porch */
.vmode = FB_VMODE_NONINTERLACED,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
},
/* 640x480p 60hz: EIA/CEA-861-B Format 1 */
@@ -125,7 +125,7 @@ static const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
.right_margin = 16, /* h_front_porch */
.lower_margin = 10, /* v_front_porch */
.vmode = FB_VMODE_NONINTERLACED,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
},
/* 720x576p 50hz EIA/CEA-861-B Formats 17 & 18 */
@@ -140,7 +140,7 @@ static const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
.right_margin = 12, /* h_front_porch */
.lower_margin = 5, /* v_front_porch */
.vmode = FB_VMODE_NONINTERLACED,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
},
/* 1920x1080p 59.94/60hz EIA/CEA-861-B Format 16 */
@@ -1142,16 +1142,23 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
val = _tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PWR);
} while (val & SOR_PWR_SETTING_NEW_PENDING);
- _tegra_hdmi_writel(hdmi,
- SOR_STATE_ASY_CRCMODE_COMPLETE |
- SOR_STATE_ASY_OWNER_HEAD0 |
- SOR_STATE_ASY_SUBOWNER_BOTH |
- SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A |
- /* TODO: to look at hsync polarity */
- SOR_STATE_ASY_HSYNCPOL_POS |
- SOR_STATE_ASY_VSYNCPOL_POS |
- SOR_STATE_ASY_DEPOL_POS,
- HDMI_NV_PDISP_SOR_STATE2);
+ val = SOR_STATE_ASY_CRCMODE_COMPLETE |
+ SOR_STATE_ASY_OWNER_HEAD0 |
+ SOR_STATE_ASY_SUBOWNER_BOTH |
+ SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A |
+ SOR_STATE_ASY_DEPOL_POS;
+
+ if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC)
+ val |= SOR_STATE_ASY_HSYNCPOL_NEG;
+ else
+ val |= SOR_STATE_ASY_HSYNCPOL_POS;
+
+ if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC)
+ val |= SOR_STATE_ASY_VSYNCPOL_NEG;
+ else
+ val |= SOR_STATE_ASY_VSYNCPOL_POS;
+
+ tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE2);
val = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL;
_tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE1);
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 2f51c47a67ab..01b3d756b930 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -209,6 +209,14 @@ static int tegra_fb_set_par(struct fb_info *info)
info->mode->lower_margin;
}
+ mode.flags = 0;
+
+ if (!(info->mode->sync & FB_SYNC_HOR_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
+
+ if (!(info->mode->sync & FB_SYNC_VERT_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
+
tegra_dc_set_mode(tegra_fb->win->dc, &mode);
tegra_fb->win->w = info->mode->xres;
@@ -776,9 +784,8 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->var.yres_virtual = fb_data->yres * 2;
info->var.bits_per_pixel = fb_data->bits_per_pixel;
info->var.activate = FB_ACTIVATE_VBL;
- /* TODO: fill in the following by querying the DC */
- info->var.height = -1;
- info->var.width = -1;
+ info->var.height = tegra_dc_get_out_height(dc);
+ info->var.width = tegra_dc_get_out_width(dc);
info->var.pixclock = 0;
info->var.left_margin = 0;
info->var.right_margin = 0;
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index c1cfd6ee229c..d533310e3999 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -22,7 +22,7 @@
#include "dev.h"
-#ifdef CONFIG_DEBUG_FS
+static struct nvhost_master *debug_master;
enum {
NVHOST_DBG_STATE_CMD = 0,
@@ -134,6 +134,28 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
nvhost_module_busy(&m->mod);
+ seq_printf(s, "---- mlocks ----\n");
+ for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
+ u32 owner = readl(m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0 + i * 4);
+ if (owner & 0x1)
+ seq_printf(s, "%d: locked by channel %d\n", i, (owner >> 8) * 0xff);
+ else if (owner & 0x2)
+ seq_printf(s, "%d: locked by cpu\n", i);
+ else
+ seq_printf(s, "%d: unlocked\n", i);
+ }
+ seq_printf(s, "\n---- syncpts ----\n");
+ for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
+ u32 max = nvhost_syncpt_read_max(&m->syncpt, i);
+ if (!max)
+ continue;
+ seq_printf(s, "id %d (%s) min %d max %d\n",
+ i, nvhost_syncpt_name(i),
+ nvhost_syncpt_update_min(&m->syncpt, i), max);
+
+ }
+
+ seq_printf(s, "\n---- channels ----\n");
for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
void __iomem *regs = m->channels[i].aperture;
u32 dmaput, dmaget, dmactrl;
@@ -152,15 +174,18 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
cbread = readl(m->aperture + HOST1X_SYNC_CBREAD(i));
cbstat = readl(m->aperture + HOST1X_SYNC_CBSTAT(i));
+ seq_printf(s, "%d-%s (%d): ", i, m->channels[i].mod.name,
+ m->channels[i].mod.refcount);
+
if (dmactrl != 0x0 || !m->channels[i].cdma.push_buffer.mapped) {
- seq_printf(s, "%d: inactive\n\n", i);
+ seq_printf(s, "inactive\n\n");
continue;
}
switch (cbstat) {
case 0x00010008:
- seq_printf(s, "%d: waiting on syncpt %d val %d\n",
- i, cbread >> 24, cbread & 0xffffff);
+ seq_printf(s, "waiting on syncpt %d val %d\n",
+ cbread >> 24, cbread & 0xffffff);
break;
case 0x00010009:
@@ -169,13 +194,13 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
val = readl(m->aperture + HOST1X_SYNC_SYNCPT_BASE(base)) & 0xffff;
val += cbread & 0xffff;
- seq_printf(s, "%d: waiting on syncpt %d val %d\n",
- i, cbread >> 24, val);
+ seq_printf(s, "waiting on syncpt %d val %d\n",
+ cbread >> 24, val);
break;
default:
- seq_printf(s, "%d: active class %02x, offset %04x, val %08x\n",
- i, cbstat >> 16, cbstat & 0xffff, cbread);
+ seq_printf(s, "active class %02x, offset %04x, val %08x\n",
+ cbstat >> 16, cbstat & 0xffff, cbread);
break;
}
@@ -244,6 +269,7 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
return 0;
}
+#ifdef CONFIG_DEBUG_FS
static int nvhost_debug_open(struct inode *inode, struct file *file)
{
@@ -259,12 +285,44 @@ static const struct file_operations nvhost_debug_fops = {
void nvhost_debug_init(struct nvhost_master *master)
{
+ debug_master = master;
debugfs_create_file("tegra_host", S_IRUGO, NULL, master, &nvhost_debug_fops);
}
#else
-void nvhost_debug_add(struct nvhost_master *master)
+void nvhost_debug_init(struct nvhost_master *master)
{
+ debug_master = master;
}
#endif
+static char nvhost_debug_dump_buff[16 * 1024];
+
+void nvhost_debug_dump(void)
+{
+ struct seq_file s;
+ int i;
+ char c;
+
+ memset(&s, 0x0, sizeof(s));
+
+ s.buf = nvhost_debug_dump_buff;
+ s.size = sizeof(nvhost_debug_dump_buff);
+ s.private = debug_master;
+
+ nvhost_debug_show(&s, NULL);
+
+ i = 0;
+ while (i < s.count ) {
+ if ((s.count - i) > 256) {
+ c = s.buf[i + 256];
+ s.buf[i + 256] = 0;
+ printk("%s", s.buf + i);
+ s.buf[i + 256] = c;
+ } else {
+ printk("%s", s.buf + i);
+ }
+ i += 256;
+ }
+}
+
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h
index ae9847c2bd74..4f71ff5d9a9d 100644
--- a/drivers/video/tegra/host/dev.h
+++ b/drivers/video/tegra/host/dev.h
@@ -48,5 +48,6 @@ struct nvhost_master {
};
void nvhost_debug_init(struct nvhost_master *master);
+void nvhost_debug_dump(void);
#endif
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 361a74a6a7cf..c2152287506f 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -28,6 +28,8 @@
#include <mach/powergate.h>
#include <mach/clk.h>
+#include "dev.h"
+
#define ACM_TIMEOUT 1*HZ
#define DISABLE_3D_POWERGATING
@@ -218,10 +220,16 @@ static void debug_not_idle(struct nvhost_module *mod)
void nvhost_module_suspend(struct nvhost_module *mod, bool system_suspend)
{
+ int ret;
+
if (system_suspend && (!is_module_idle(mod)))
debug_not_idle(mod);
- wait_event(mod->idle, is_module_idle(mod));
+ ret = wait_event_timeout(mod->idle, is_module_idle(mod),
+ ACM_TIMEOUT + msecs_to_jiffies(500));
+ if (ret == 0)
+ nvhost_debug_dump();
+
if (system_suspend)
printk("tegra_grhost: entered idle\n");
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index 674b34ab6f45..2cea073499b7 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -48,6 +48,13 @@
#define NVMAP_NUM_PTES 64
#define NVMAP_CARVEOUT_KILLER_RETRY_TIME 100 /* msecs */
+#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
+static bool carveout_killer = true;
+#else
+static bool carveout_killer;
+#endif
+module_param(carveout_killer, bool, 0640);
+
struct nvmap_carveout_node {
unsigned int heap_bit;
struct nvmap_heap *carveout;
@@ -324,8 +331,8 @@ static struct nvmap_client* get_client_from_carveout_commit(
carveout_commit);
}
-#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
static DECLARE_WAIT_QUEUE_HEAD(wait_reclaim);
+static int wait_count;
bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
{
struct nvmap_carveout_commit *commit;
@@ -359,6 +366,9 @@ bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
sig = task->signal;
if (!task->mm || !sig)
goto end;
+ /* don't try to kill current */
+ if (task == current->group_leader)
+ goto end;
/* don't try to kill higher priority tasks */
if (sig->oom_adj < current_oom_adj)
goto end;
@@ -374,22 +384,22 @@ end:
task_unlock(task);
}
if (selected_task) {
- wait = selected_task != current;
+ wait = true;
if (fatal_signal_pending(selected_task)) {
pr_warning("carveout_killer: process %d dying "
"slowly\n", selected_task->pid);
goto out;
}
pr_info("carveout_killer: killing process %d with oom_adj %d "
- "to reclaim %d\n", selected_task->pid, selected_oom_adj,
- selected_size);
+ "to reclaim %d (for process with oom_adj %d)\n",
+ selected_task->pid, selected_oom_adj,
+ selected_size, current_oom_adj);
force_sig(SIGKILL, selected_task);
}
out:
spin_unlock_irqrestore(&node->clients_lock, flags);
return wait;
}
-#endif
struct nvmap_heap_block *do_nvmap_carveout_alloc(struct nvmap_client *client,
size_t len, size_t align,
@@ -422,63 +432,75 @@ struct nvmap_heap_block *do_nvmap_carveout_alloc(struct nvmap_client *client,
return NULL;
}
+static bool nvmap_carveout_freed(int count)
+{
+ smp_rmb();
+ return count != wait_count;
+}
+
struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
size_t len, size_t align,
unsigned long usage,
unsigned int prot)
{
struct nvmap_heap_block *block;
-#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
struct nvmap_carveout_node *co_heap;
struct nvmap_device *dev = client->dev;
int i;
unsigned long end = jiffies +
msecs_to_jiffies(NVMAP_CARVEOUT_KILLER_RETRY_TIME);
int count = 0;
- DEFINE_WAIT(wait);
do {
- block = do_nvmap_carveout_alloc(client, len, align, usage,
- prot);
+ block = do_nvmap_carveout_alloc(client, len, align,
+ usage, prot);
+ if (!carveout_killer)
+ return block;
+
if (block)
return block;
- if (!count++)
- printk("%s: failed to allocate %u bytes, "
- "firing carveout killer!\n", __func__, len);
- else
- printk("%s: still can't allocate %u bytes, "
- "attempt %d!\n", __func__, len, count);
+ if (!count++) {
+ char task_comm[TASK_COMM_LEN];
+ if (client->task)
+ get_task_comm(task_comm, client->task);
+ else
+ task_comm[0] = 0;
+ pr_info("%s: failed to allocate %u bytes for "
+ "process %s, firing carveout "
+ "killer!\n", __func__, len, task_comm);
+
+ } else {
+ pr_info("%s: still can't allocate %u bytes, "
+ "attempt %d!\n", __func__, len, count);
+ }
/* shrink carveouts that matter and try again */
for (i = 0; i < dev->nr_carveouts; i++) {
+ int count;
co_heap = &dev->heaps[i];
if (!(co_heap->heap_bit & usage))
continue;
- /* indicates we just delivered a sigkill to current,
- or didn't find anything to kill might as well stop
- trying */
+ count = wait_count;
+ /* indicates we didn't find anything to kill,
+ might as well stop trying */
if (!nvmap_shrink_carveout(co_heap))
return NULL;
- prepare_to_wait(&wait_reclaim, &wait,
- TASK_INTERRUPTIBLE);
- schedule_timeout(end - jiffies);
- finish_wait(&wait_reclaim, &wait);
+ if (time_is_after_jiffies(end))
+ wait_event_interruptible_timeout(wait_reclaim,
+ nvmap_carveout_freed(count),
+ end - jiffies);
}
} while (time_is_after_jiffies(end));
if (time_is_before_jiffies(end))
- printk("carveout_killer: timeout expired without allocation "
- "succeeding.\n");
+ pr_info("carveout_killer: timeout expired without "
+ "allocation succeeding.\n");
return NULL;
-#else
- block = do_nvmap_carveout_alloc(client, len, align, usage, prot);
- return block;
-#endif
}
/* remove a handle from the device's tree of all handles; called
@@ -588,17 +610,17 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
client->carveout_commit[i].commit = 0;
}
- get_task_struct(current);
- task_lock(current);
+ get_task_struct(current->group_leader);
+ task_lock(current->group_leader);
/* don't bother to store task struct for kernel threads,
they can't be killed anyway */
if (current->flags & PF_KTHREAD) {
- put_task_struct(current);
+ put_task_struct(current->group_leader);
task = NULL;
} else {
- task = current;
+ task = current->group_leader;
}
- task_unlock(current);
+ task_unlock(current->group_leader);
client->task = task;
spin_lock_init(&client->ref_lock);
@@ -641,9 +663,11 @@ static void destroy_client(struct nvmap_client *client)
kfree(ref);
}
-#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
- wake_up_all(&wait_reclaim);
-#endif
+ if (carveout_killer) {
+ wait_count++;
+ smp_wmb();
+ wake_up_all(&wait_reclaim);
+ }
for (i = 0; i < client->dev->nr_carveouts; i++)
list_del(&client->carveout_commit[i].list);