summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNitin Kumbhar <nkumbhar@nvidia.com>2011-02-04 17:08:18 +0530
committerNitin Kumbhar <nkumbhar@nvidia.com>2011-02-04 17:08:18 +0530
commitb6b1f33f279fcb1c4a751f981153affa6469e94c (patch)
treea77ace4c91f29d814982c40bea8c4a172af9ee3e
parentdf4a2fbff8471de3f75d55b93e2bf94dfd26ff7e (diff)
parenta979d00287bcd3297bd13a59534073e6faa570c9 (diff)
merging android-tegra-2.6.36 into git-master/linux-2.6/android-tegra-2.6.36
Conflicts: arch/arm/mach-tegra/include/mach/dc.h drivers/video/tegra/dc/hdmi.c drivers/video/tegra/host/nvhost_acm.c Change-Id: Iddf74984cc02f08dca3738967c0580ba7c375337
-rw-r--r--arch/arm/kernel/entry-armv.S3
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h10
-rw-r--r--arch/arm/mach-tegra/tegra_i2s_audio.c37
-rw-r--r--arch/arm/mach-tegra/usb_phy.c11
-rw-r--r--arch/arm/vfp/entry.S3
-rw-r--r--drivers/base/power/main.c50
-rw-r--r--drivers/cpufreq/cpufreq_stats.c30
-rw-r--r--drivers/usb/gadget/fsl_tegra_udc.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c2
-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
-rw-r--r--drivers/watchdog/tegra_wdt.c45
-rw-r--r--kernel/irq/pm.c6
19 files changed, 316 insertions, 148 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/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index b4453f4c2ac3..1dc9c556d6fa 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -38,8 +38,12 @@ struct tegra_dc_mode {
int h_front_porch;
int v_front_porch;
int stereo_mode;
+ 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,
@@ -84,6 +88,9 @@ struct tegra_dc_out {
unsigned depth;
unsigned dither;
+ unsigned height; /* mm */
+ unsigned width; /* mm */
+
struct tegra_dc_mode *modes;
int n_modes;
@@ -214,4 +221,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/arch/arm/mach-tegra/tegra_i2s_audio.c b/arch/arm/mach-tegra/tegra_i2s_audio.c
index 45e4cc5ee6f4..1bae833f4f2a 100644
--- a/arch/arm/mach-tegra/tegra_i2s_audio.c
+++ b/arch/arm/mach-tegra/tegra_i2s_audio.c
@@ -611,15 +611,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 *);
@@ -716,12 +716,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,
@@ -742,7 +742,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,
@@ -766,7 +766,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,
@@ -777,7 +777,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,
@@ -791,12 +791,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],
@@ -807,7 +807,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],
@@ -1122,7 +1122,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:
@@ -1187,9 +1189,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:
@@ -1277,7 +1279,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:
@@ -1897,7 +1900,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) {
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 9030545d4bdc..9e809253170f 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -157,7 +157,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)
@@ -442,6 +442,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;
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
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"));
@@ -618,29 +618,6 @@ static void dpm_drv_timeout(unsigned long data)
}
/**
- * 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) {
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 = {
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.
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 5e14bfbe148c..5765496218a1 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -645,7 +645,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) {
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);
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",
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;
}