From 28b85f11c6dc65ac2c70f159a8210a4dd9554881 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Mon, 24 Jan 2011 12:35:11 -0800 Subject: video: tegra: dump host state when timing out on suspend Change-Id: I718fb071ac74f5a051a7d5b9fcdd782163ed48b6 Signed-off-by: Erik Gilling --- drivers/video/tegra/host/debug.c | 76 ++++++++++++++++++++++++++++++----- drivers/video/tegra/host/dev.h | 1 + drivers/video/tegra/host/nvhost_acm.c | 9 ++++- 3 files changed, 76 insertions(+), 10 deletions(-) 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 cf542be8a645..ef8f1ea2c13a 100644 --- a/drivers/video/tegra/host/nvhost_acm.c +++ b/drivers/video/tegra/host/nvhost_acm.c @@ -28,6 +28,8 @@ #include #include +#include "dev.h" + #define ACM_TIMEOUT 1*HZ #define DISABLE_3D_POWERGATING @@ -194,7 +196,12 @@ static int is_module_idle(struct nvhost_module *mod) void nvhost_module_suspend(struct nvhost_module *mod) { - wait_event(mod->idle, is_module_idle(mod)); + int ret; + + ret = wait_event_timeout(mod->idle, is_module_idle(mod), + ACM_TIMEOUT + msecs_to_jiffies(500)); + if (ret == 0) + nvhost_debug_dump(); flush_delayed_work(&mod->powerdown); BUG_ON(mod->powered); } -- cgit v1.2.3 From eac4ccd16357ad77f34c28813d8fcf35ba81fa33 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Mon, 24 Jan 2011 14:36:39 -0800 Subject: Print pending wakeup IRQ preventing suspend to dmesg Change-Id: I36f90735c75fb7c7ab1084775ec0d0ab02336e6e Signed-off-by: Todd Poynor --- kernel/irq/pm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 0d4005d85b03..1df62ef4713b 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -72,8 +72,12 @@ int check_wakeup_irqs(void) int irq; for_each_irq_desc(irq, desc) - if ((desc->status & IRQ_WAKEUP) && (desc->status & IRQ_PENDING)) + if ((desc->status & IRQ_WAKEUP) && + (desc->status & IRQ_PENDING)) { + pr_info("Wakeup IRQ %d %s pending, suspend aborted\n", + irq, desc->name ? desc->name : ""); return -EBUSY; + } return 0; } -- cgit v1.2.3 From 22dcde2e8476b5db4774542edd5b01a498b825a5 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Mon, 24 Jan 2011 15:28:31 -0800 Subject: video: tegra: incresase delay in underflow recovery Change-Id: I8093c83a2749c63b6ece051cc9b892d87e55fe04 Signed-off-by: Erik Gilling --- drivers/video/tegra/dc/dc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 29be689fcaff..c57a8f9ded4f 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -1087,8 +1087,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); -- cgit v1.2.3 From 82fa87e2ca94100efcd801df979e222bce0b01d7 Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Zavin Date: Mon, 24 Jan 2011 14:16:47 -0800 Subject: video: tegra: nvmap: Several changes to carveout killer -Add a module param to enable/disable carveout killer -Fix race condition in code to wait for something to free memory after firing carveout killer -Fix the check for current so we always compare task->group_leaders Change-Id: Ie030978827dce6b0fbbfa1db0d80e4abe59eaa51 Signed-off-by: Rebecca Schultz Zavin --- drivers/video/tegra/nvmap/nvmap_dev.c | 96 ++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 36 deletions(-) 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); -- cgit v1.2.3 From 2418fe42cc2e73531c6369cf7c77f135c8b04d42 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Tue, 25 Jan 2011 12:13:52 -0800 Subject: usb: gadget: tegra_udc: Request 400MHz emc clock while USB is active to eliminate all USB buffer underruns. Change-Id: I7ad8ebfa2d802f91b81839e14fde906da1a0569e Signed-off-by: Nathan Connell --- drivers/usb/gadget/fsl_tegra_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c index 74c1d0b52541..14e62f40a50a 100644 --- a/drivers/usb/gadget/fsl_tegra_udc.c +++ b/drivers/usb/gadget/fsl_tegra_udc.c @@ -42,7 +42,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) } clk_enable(emc_clk); - clk_set_rate(emc_clk, 240000000); + clk_set_rate(emc_clk, 400000000); /* we have to remap the registers ourselves as fsl_udc does not * export them for us. -- cgit v1.2.3 From 3f0fad7ec42752a333787554fab28cffd3211688 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Tue, 25 Jan 2011 12:14:52 -0800 Subject: usb: host: tegra: Request 400MHz emc clock while USB is active to eliminate all USB buffer underruns. Change-Id: I9977224601e715e950284708958be98d37b3e6b1 Signed-off-by: Nathan Connell --- drivers/usb/host/ehci-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index bd6fb0144c26..3c72ed4c6cdc 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -548,7 +548,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) } clk_enable(tegra->emc_clk); - clk_set_rate(tegra->emc_clk, 240000000); + clk_set_rate(tegra->emc_clk, 400000000); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { -- cgit v1.2.3 From 41fec00c4b01ac43b19bba39422c85d00487a98b Mon Sep 17 00:00:00 2001 From: Dmitriy Gruzman Date: Mon, 24 Jan 2011 20:52:02 -0600 Subject: watchdog: tegra_wdt: Several changes to watchdog driver Fix not re-enabling watchdog resume if it was enabled in probe Add clearing watchdog interrupt in probe Remove tegra_wdt_set_timeout Change-Id: I8fdbb6da3eda64a85a73ed85ab979a5ee0261c37 Signed-off-by: Dmitriy Gruzman --- drivers/watchdog/tegra_wdt.c | 45 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index d7ad6238d4f3..d11b99816ca6 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c @@ -40,17 +40,17 @@ #define MAX_WDT_PERIOD 1000 #define TIMER_PTV 0x0 - #define TIMER_EN (1 << 31) - #define TIMER_PERIODIC (1 << 30) +#define TIMER_EN (1 << 31) +#define TIMER_PERIODIC (1 << 30) #define TIMER_PCR 0x4 - #define TIMER_PCR_INTR (1 << 30) +#define TIMER_PCR_INTR (1 << 30) #define WDT_EN (1 << 5) #define WDT_SEL_TMR1 (0 << 4) #define WDT_SYS_RST (1 << 2) -static int heartbeat = 30; +static int heartbeat = 30; /* must be greater than MIN_WDT_PERIOD and lower than MAX_WDT_PERIOD */ struct tegra_wdt { struct miscdevice miscdev; @@ -67,31 +67,13 @@ struct tegra_wdt { static struct tegra_wdt *tegra_wdt_dev; -static void tegra_wdt_set_timeout(struct tegra_wdt *wdt, int sec) -{ - u32 ptv, src; - - ptv = readl(wdt->wdt_timer + TIMER_PTV); - src = readl(wdt->wdt_source); - - writel(0, wdt->wdt_source); - wdt->timeout = clamp(sec, MIN_WDT_PERIOD, MAX_WDT_PERIOD); - if (ptv & TIMER_EN) { - /* since the watchdog reset occurs when a second interrupt - * is asserted before the first is processed, program the - * timer period to one-half of the watchdog period */ - ptv = wdt->timeout * 1000000ul / 2; - ptv |= (TIMER_EN | TIMER_PERIODIC); - writel(ptv, wdt->wdt_timer + TIMER_PTV); - } - writel(src, wdt->wdt_source); -} - - static void tegra_wdt_enable(struct tegra_wdt *wdt) { u32 val; + /* since the watchdog reset occurs when a second interrupt + * is asserted before the first is processed, program the + * timer period to one-half of the watchdog period */ val = wdt->timeout * 1000000ul / 2; val |= (TIMER_EN | TIMER_PERIODIC); writel(val, wdt->wdt_timer + TIMER_PTV); @@ -133,7 +115,7 @@ static int tegra_wdt_open(struct inode *inode, struct file *file) return -EBUSY; wdt->enabled = true; - tegra_wdt_set_timeout(wdt, heartbeat); + wdt->timeout = heartbeat; tegra_wdt_enable(wdt); file->private_data = wdt; return nonseekable_open(inode, file); @@ -179,7 +161,7 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd, return -EFAULT; spin_lock(&lock); tegra_wdt_disable(wdt); - tegra_wdt_set_timeout(wdt, new_timeout); + wdt->timeout = clamp(new_timeout, MIN_WDT_PERIOD, MAX_WDT_PERIOD); tegra_wdt_enable(wdt); spin_unlock(&lock); case WDIOC_GETTIMEOUT: @@ -268,6 +250,7 @@ static int tegra_wdt_probe(struct platform_device *pdev) dev_info(&pdev->dev, "last reset due to watchdog timeout\n"); tegra_wdt_disable(wdt); + writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR); ret = request_irq(res_irq->start, tegra_wdt_interrupt, IRQF_DISABLED, dev_name(&pdev->dev), wdt); @@ -280,8 +263,6 @@ static int tegra_wdt_probe(struct platform_device *pdev) wdt->res_src = res_src; wdt->res_wdt = res_wdt; - wdt->timeout = heartbeat; - ret = register_reboot_notifier(&wdt->notifier); if (ret) { dev_err(&pdev->dev, "cannot register reboot notifier\n"); @@ -298,6 +279,8 @@ static int tegra_wdt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wdt); tegra_wdt_dev = wdt; #ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE + wdt->enabled = true; + wdt->timeout = heartbeat; tegra_wdt_enable(wdt); #endif return 0; @@ -334,6 +317,7 @@ static int tegra_wdt_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM static int tegra_wdt_suspend(struct platform_device *pdev, pm_message_t state) { struct tegra_wdt *wdt = platform_get_drvdata(pdev); @@ -351,12 +335,15 @@ static int tegra_wdt_resume(struct platform_device *pdev) return 0; } +#endif static struct platform_driver tegra_wdt_driver = { .probe = tegra_wdt_probe, .remove = __devexit_p(tegra_wdt_remove), +#ifdef CONFIG_PM .suspend = tegra_wdt_suspend, .resume = tegra_wdt_resume, +#endif .driver = { .owner = THIS_MODULE, .name = "tegra_wdt", -- cgit v1.2.3 From 769922c5aa726ddb100548f4df6cbe0c40503666 Mon Sep 17 00:00:00 2001 From: Nathan Connell Date: Wed, 12 Jan 2011 14:32:24 -0600 Subject: ARM: tegra: usb_phy: Configure USB1 PHY to use programmed value instead of fused value. This is required to meet High Speed USB signaling requirements. Change-Id: I659b33faa950605ecf040598112e1972047ae7ad Signed-off-by: Nathan Connell --- arch/arm/mach-tegra/usb_phy.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 13e502cd0490..7242dda542c2 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -136,7 +136,7 @@ #define UTMIP_PD_CHRG (1 << 0) #define UTMIP_SPARE_CFG0 0x834 -#define FUSE_SETUP_SEL (1 << 3); +#define FUSE_SETUP_SEL (1 << 3) #define UTMIP_XCVR_CFG1 0x838 #define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) @@ -420,6 +420,15 @@ static void utmi_phy_power_on(struct tegra_usb_phy *phy) val |= UTMIP_BIAS_PDTRK_COUNT(0x5); writel(val, base + UTMIP_BIAS_CFG1); + if (phy->instance == 0) { + val = readl(base + UTMIP_SPARE_CFG0); + if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) + val &= ~FUSE_SETUP_SEL; + else + val |= FUSE_SETUP_SEL; + writel(val, base + UTMIP_SPARE_CFG0); + } + if (phy->instance == 2) { val = readl(base + USB_SUSP_CTRL); val |= UTMIP_PHY_ENABLE; -- cgit v1.2.3 From 6f0193721acf50368b585e3fad8c206049e2e07a Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Wed, 26 Jan 2011 18:28:33 -0800 Subject: PM: Change dpm watchdog to support async suspend Exclude from the watchdog the time spent waiting for children that are resumed asynchronously and time every devices, whether or not they resumed synchronously. Change-Id: I84209dfd5df72842e045096c906fd61e20e6d183 Signed-off-by: Benoit Goby --- drivers/base/power/main.c | 50 +++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 33f9aafb47fb..4ff491f49ee4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -47,11 +47,10 @@ static DEFINE_MUTEX(dpm_list_mtx); static pm_message_t pm_transition; static void dpm_drv_timeout(unsigned long data); -static DEFINE_TIMER(dpm_drv_wd, dpm_drv_timeout, 0, 0); -static struct { +struct dpm_drv_wd_data { struct device *dev; struct task_struct *tsk; -} dpm_drv_wd_data; +}; /* * Set once the preparation of devices for a PM transition has started, reset @@ -605,8 +604,9 @@ static bool is_async(struct device *dev) */ static void dpm_drv_timeout(unsigned long data) { - struct device *dev = dpm_drv_wd_data.dev; - struct task_struct *tsk = dpm_drv_wd_data.tsk; + struct dpm_drv_wd_data *wd_data = (void *)data; + struct device *dev = wd_data->dev; + struct task_struct *tsk = wd_data->tsk; printk(KERN_EMERG "**** DPM device timeout: %s (%s)\n", dev_name(dev), (dev->driver ? dev->driver->name : "no driver")); @@ -617,29 +617,6 @@ static void dpm_drv_timeout(unsigned long data) BUG(); } -/** - * dpm_drv_wdset - Sets up driver suspend/resume watchdog timer. - * @dev: struct device which we're guarding. - * - */ -static void dpm_drv_wdset(struct device *dev) -{ - dpm_drv_wd_data.dev = dev; - dpm_drv_wd_data.tsk = get_current(); - dpm_drv_wd.data = (unsigned long) &dpm_drv_wd_data; - mod_timer(&dpm_drv_wd, jiffies + (HZ * 3)); -} - -/** - * dpm_drv_wdclr - clears driver suspend/resume watchdog timer. - * @dev: struct device which we're no longer guarding. - * - */ -static void dpm_drv_wdclr(struct device *dev) -{ - del_timer_sync(&dpm_drv_wd); -} - /** * dpm_resume - Execute "resume" callbacks for non-sysdev devices. * @state: PM transition of the system being carried out. @@ -896,8 +873,19 @@ static int async_error; static int __device_suspend(struct device *dev, pm_message_t state, bool async) { int error = 0; + struct timer_list timer; + struct dpm_drv_wd_data data; dpm_wait_for_children(dev, async); + + data.dev = dev; + data.tsk = get_current(); + init_timer_on_stack(&timer); + timer.expires = jiffies + HZ * 3; + timer.function = dpm_drv_timeout; + timer.data = (unsigned long)&data; + add_timer(&timer); + device_lock(dev); if (async_error) @@ -939,6 +927,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) End: device_unlock(dev); + + del_timer_sync(&timer); + destroy_timer_on_stack(&timer); + complete_all(&dev->power.completion); return error; @@ -991,9 +983,7 @@ static int dpm_suspend(pm_message_t state) get_device(dev); mutex_unlock(&dpm_list_mtx); - dpm_drv_wdset(dev); error = device_suspend(dev); - dpm_drv_wdclr(dev); mutex_lock(&dpm_list_mtx); if (error) { -- cgit v1.2.3 From a0bcb8eabafef53e13050042d4b583f088535b0f Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 28 Jan 2011 09:13:22 -0800 Subject: [ARM] tegra_i2s_audio: separate TX/RX DMA setup Fixed a problem preventing independent setup/teardown of TX and RX DMAs when setting playback or capture buffer count. Signed-off-by: Eric Laurent --- arch/arm/mach-tegra/tegra_i2s_audio.c | 37 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-tegra/tegra_i2s_audio.c b/arch/arm/mach-tegra/tegra_i2s_audio.c index 331d4af6a85b..a519e85e1dc9 100644 --- a/arch/arm/mach-tegra/tegra_i2s_audio.c +++ b/arch/arm/mach-tegra/tegra_i2s_audio.c @@ -606,15 +606,15 @@ static int i2s_configure(struct platform_device *pdev) static int init_stream_buffer(struct audio_stream *, int); -static int setup_dma(struct audio_driver_state *); -static void tear_down_dma(struct audio_driver_state *); +static int setup_dma(struct audio_driver_state *, int); +static void tear_down_dma(struct audio_driver_state *, int); static void stop_dma_playback(struct audio_stream *); static int start_dma_recording(struct audio_stream *, int); static void stop_dma_recording(struct audio_stream *); struct sound_ops { - int (*setup)(struct audio_driver_state *); - void (*tear_down)(struct audio_driver_state *); + int (*setup)(struct audio_driver_state *, int); + void (*tear_down)(struct audio_driver_state *, int); void (*stop_playback)(struct audio_stream *); int (*start_recording)(struct audio_stream *, int); void (*stop_recording)(struct audio_stream *); @@ -711,12 +711,12 @@ static void setup_dma_tx_request(struct tegra_dma_req *req, static void setup_dma_rx_request(struct tegra_dma_req *req, struct audio_stream *ais); -static int setup_dma(struct audio_driver_state *ads) +static int setup_dma(struct audio_driver_state *ads, int mask) { int rc, i; pr_info("%s\n", __func__); - if ((ads->pdata->mask & TEGRA_AUDIO_ENABLE_TX)) { + if (mask & TEGRA_AUDIO_ENABLE_TX) { /* setup audio playback */ for (i = 0; i < ads->out.num_bufs; i++) { ads->out.buf_phy[i] = dma_map_single(&ads->pdev->dev, @@ -737,7 +737,7 @@ static int setup_dma(struct audio_driver_state *ads) } } - if ((ads->pdata->mask & TEGRA_AUDIO_ENABLE_RX)) { + if (mask & TEGRA_AUDIO_ENABLE_RX) { /* setup audio recording */ for (i = 0; i < ads->in.num_bufs; i++) { ads->in.buf_phy[i] = dma_map_single(&ads->pdev->dev, @@ -761,7 +761,7 @@ static int setup_dma(struct audio_driver_state *ads) return 0; fail_rx: - if (ads->pdata->mask & TEGRA_AUDIO_ENABLE_RX) { + if (mask & TEGRA_AUDIO_ENABLE_RX) { for (i = 0; i < ads->in.num_bufs; i++) { dma_unmap_single(&ads->pdev->dev, ads->in.buf_phy[i], 1 << PCM_BUFFER_MAX_SIZE_ORDER, @@ -772,7 +772,7 @@ fail_rx: ads->in.dma_chan = 0; } fail_tx: - if (ads->pdata->mask & TEGRA_AUDIO_ENABLE_TX) { + if (mask & TEGRA_AUDIO_ENABLE_TX) { for (i = 0; i < ads->out.num_bufs; i++) { dma_unmap_single(&ads->pdev->dev, ads->out.buf_phy[i], 1 << PCM_BUFFER_MAX_SIZE_ORDER, @@ -786,12 +786,12 @@ fail_tx: return rc; } -static void tear_down_dma(struct audio_driver_state *ads) +static void tear_down_dma(struct audio_driver_state *ads, int mask) { int i; pr_info("%s\n", __func__); - if (ads->pdata->mask & TEGRA_AUDIO_ENABLE_TX) { + if (mask & TEGRA_AUDIO_ENABLE_TX) { tegra_dma_free_channel(ads->out.dma_chan); for (i = 0; i < ads->out.num_bufs; i++) { dma_unmap_single(&ads->pdev->dev, ads->out.buf_phy[i], @@ -802,7 +802,7 @@ static void tear_down_dma(struct audio_driver_state *ads) } ads->out.dma_chan = NULL; - if (ads->pdata->mask & TEGRA_AUDIO_ENABLE_RX) { + if (mask & TEGRA_AUDIO_ENABLE_RX) { tegra_dma_free_channel(ads->in.dma_chan); for (i = 0; i < ads->in.num_bufs; i++) { dma_unmap_single(&ads->pdev->dev, ads->in.buf_phy[i], @@ -1117,7 +1117,9 @@ static long tegra_audio_out_ioctl(struct file *file, if (rc < 0) break; aos->num_bufs = num; - sound_ops->setup(ads); + sound_ops->tear_down(ads, TEGRA_AUDIO_ENABLE_TX); + sound_ops->setup(ads, TEGRA_AUDIO_ENABLE_TX); + pr_debug("%s: num buf set to %d\n", __func__, num); } break; case TEGRA_AUDIO_OUT_GET_NUM_BUFS: @@ -1182,9 +1184,9 @@ static long tegra_audio_ioctl(struct file *file, rc = -EBUSY; goto done; } - sound_ops->tear_down(ads); + sound_ops->tear_down(ads, ads->pdata->mask); i2s_configure(ads->pdev); - sound_ops->setup(ads); + sound_ops->setup(ads, ads->pdata->mask); } done: @@ -1272,7 +1274,8 @@ static long tegra_audio_in_ioctl(struct file *file, if (rc < 0) break; ais->num_bufs = num; - sound_ops->setup(ads); + sound_ops->tear_down(ads, TEGRA_AUDIO_ENABLE_RX); + sound_ops->setup(ads, TEGRA_AUDIO_ENABLE_RX); } break; case TEGRA_AUDIO_IN_GET_NUM_BUFS: @@ -1880,7 +1883,7 @@ static int tegra_audio_probe(struct platform_device *pdev) if (rc < 0) return rc; - sound_ops->setup(state); + sound_ops->setup(state, state->pdata->mask); rc = device_create_file(&pdev->dev, &dev_attr_dma_toggle); if (rc < 0) { -- cgit v1.2.3 From fa51e1a77ebb12ca61510370e78e679a314e3dda Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 28 Jan 2011 19:32:31 -0800 Subject: cpufreq: Prevent memory leak in cpufreq_stats on hotplug Ensures that cpufreq_stats_free_table is called before __cpufreq_remove_dev on cpu hotplug (which also occurs during suspend on SMP systems) to make sure that sysfs_remove_group can get called before the cpufreq kobj is freed. Otherwise, the sysfs file structures are leaked. Change-Id: I87e55277272f5cfad47e9e7c92630e990bb90069 Signed-off-by: Colin Cross --- drivers/cpufreq/cpufreq_stats.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 00d73fc8e4e2..ca3f24c296a0 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -305,6 +305,27 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, return 0; } +static int cpufreq_stats_create_table_cpu(unsigned int cpu) +{ + struct cpufreq_policy *policy; + struct cpufreq_frequency_table *table; + int ret = -ENODEV; + + policy = cpufreq_cpu_get(cpu); + if (!policy) + return -ENODEV; + + table = cpufreq_frequency_get_table(cpu); + if (!table) + goto out; + + ret = cpufreq_stats_create_table(policy, table); + +out: + cpufreq_cpu_put(policy); + return ret; +} + static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) @@ -316,10 +337,14 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, case CPU_ONLINE_FROZEN: cpufreq_update_policy(cpu); break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: cpufreq_stats_free_table(cpu); break; + case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: + cpufreq_stats_create_table_cpu(cpu); + break; } return NOTIFY_OK; } @@ -327,6 +352,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, static struct notifier_block cpufreq_stat_cpu_notifier __refdata = { .notifier_call = cpufreq_stat_cpu_callback, + .priority = 1, }; static struct notifier_block notifier_policy_block = { -- cgit v1.2.3 From 23b6f13927416ced600e5a27f4d17ba54d857ad9 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 27 Jan 2011 15:46:20 -0800 Subject: ARM: vfp: Move exception address fixup into vfphw.S If the PC on the stack is updated in entry-armv.S, do_undefinstr can get called after the fixup. do_undefinstr does its own fixup, and doing both causes the PC to point to half way through an instruction. Instead, do the fixup in do_vfp, where only the vfp code can get called. Change-Id: I6d966887adc8ed58d88bfe0cb3c0ba29213be488 Signed-off-by: Colin Cross --- arch/arm/kernel/entry-armv.S | 3 +-- arch/arm/vfp/entry.S | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index e572d24d018d..44cb9db8dd50 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -506,8 +506,7 @@ __und_usr: blo __und_usr_unknown 3: ldrht r0, [r4] add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 - str r2, [sp, #S_PC] @ it's a 2x16bit instr, update - orr r0, r0, r5, lsl #16 @ regs->ARM_pc + orr r0, r0, r5, lsl #16 #else b __und_usr_unknown #endif diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 4fa9903b83cf..c1a978402583 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -10,7 +10,7 @@ * * Basic entry code, called from the kernel's undefined instruction trap. * r0 = faulted instruction - * r5 = faulted PC+4 + * r2 = faulted PC+4 * r9 = successful return * r10 = thread_info structure * lr = failure return @@ -26,6 +26,7 @@ ENTRY(do_vfp) str r11, [r10, #TI_PREEMPT] #endif enable_irq + str r2, [sp, #S_PC] @ update regs->ARM_pc for Thumb 2 case ldr r4, .LCvfp ldr r11, [r10, #TI_CPU] @ CPU number add r10, r10, #TI_VFPSTATE @ r10 = workspace -- cgit v1.2.3 From 7baed3b1806adb1780bf316feeb72f12c53c2102 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Tue, 1 Feb 2011 13:01:55 -0800 Subject: video: tegra: correct HDMI h/vsync polairty in some modes Change-Id: I0e988d1724461ff2d5bd1009f2fdc379bd154703 Signed-off-by: Erik Gilling --- drivers/video/tegra/dc/hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index 878cca51283a..b3eb86220ab4 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -87,7 +87,7 @@ 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 */ @@ -102,7 +102,7 @@ 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 */ @@ -117,7 +117,7 @@ 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 */ -- cgit v1.2.3 From 29cf32156dbdbb36d89edffbbe1bbda44760f7ac Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Wed, 2 Feb 2011 12:12:31 -0800 Subject: video: tegra: support v/h sync polarity Change-Id: Ida82a70efaeadc9d5b11d8703e688063680b72a8 Signed-off-by: Erik Gilling --- arch/arm/mach-tegra/include/mach/dc.h | 4 ++++ drivers/video/tegra/dc/dc.c | 12 ++++++++++++ drivers/video/tegra/dc/dc_reg.h | 4 ++++ drivers/video/tegra/fb.c | 8 ++++++++ 4 files changed, 28 insertions(+) diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index 43a9ec1e141d..9fe8d6a7e71b 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -37,8 +37,12 @@ struct tegra_dc_mode { int v_active; int h_front_porch; int v_front_porch; + u32 flags; }; +#define TEGRA_DC_MODE_FLAG_NEG_V_SYNC (1 << 0) +#define TEGRA_DC_MODE_FLAG_NEG_H_SYNC (1 << 1) + enum { TEGRA_DC_OUT_RGB, TEGRA_DC_OUT_HDMI, diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index c57a8f9ded4f..d316fde01662 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -736,6 +736,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; diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h index bd1750b78e44..ab21c6eba0e1 100644 --- a/drivers/video/tegra/dc/dc_reg.h +++ b/drivers/video/tegra/dc/dc_reg.h @@ -128,6 +128,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/fb.c b/drivers/video/tegra/fb.c index 5d6a11a4ba55..4f8a5c0270f7 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -194,6 +194,14 @@ static int tegra_fb_set_par(struct fb_info *info) mode.h_front_porch = info->mode->right_margin; mode.v_front_porch = 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; -- cgit v1.2.3 From 29c4c67185ebab213ce0b54a9292250e0f45a180 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Wed, 2 Feb 2011 15:28:32 -0800 Subject: video: tegra: set h/v sync polarity for HDMI Change-Id: I4be0eb963c3779b9313ef94476b1589059d4aa3c Signed-off-by: Erik Gilling --- drivers/video/tegra/dc/hdmi.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index b3eb86220ab4..b214f2c41db3 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -1052,16 +1052,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); -- cgit v1.2.3 From 4a6469b9eb31fdbf9183417152af4ca151ddf230 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Thu, 3 Feb 2011 13:15:50 -0800 Subject: video: tegra: add height/width to dc and fb Change-Id: I22c280928079af04263375fce63a87776588a457 Signed-off-by: Erik Gilling --- arch/arm/mach-tegra/include/mach/dc.h | 6 ++++++ drivers/video/tegra/dc/dc.c | 17 +++++++++++++++++ drivers/video/tegra/fb.c | 5 ++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index 9fe8d6a7e71b..f5a64cba61ae 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -63,6 +63,9 @@ struct tegra_dc_out { unsigned align; unsigned depth; + unsigned height; /* mm */ + unsigned width; /* mm */ + struct tegra_dc_mode *modes; int n_modes; @@ -184,4 +187,7 @@ int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n); int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode); +unsigned tegra_dc_get_out_height(struct tegra_dc *dc); +unsigned tegra_dc_get_out_width(struct tegra_dc *dc); + #endif diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index d316fde01662..1768efbc6e13 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -822,6 +822,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) { diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 4f8a5c0270f7..1f0b967acd89 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -745,9 +745,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; -- cgit v1.2.3