|
@@ -204,6 +204,14 @@ struct dsi_update_region {
|
|
|
struct omap_dss_device *device;
|
|
|
};
|
|
|
|
|
|
+struct dsi_irq_stats {
|
|
|
+ unsigned long last_reset;
|
|
|
+ unsigned irq_count;
|
|
|
+ unsigned dsi_irqs[32];
|
|
|
+ unsigned vc_irqs[4][32];
|
|
|
+ unsigned cio_irqs[32];
|
|
|
+};
|
|
|
+
|
|
|
static struct
|
|
|
{
|
|
|
void __iomem *base;
|
|
@@ -258,6 +266,11 @@ static struct
|
|
|
#endif
|
|
|
int debug_read;
|
|
|
int debug_write;
|
|
|
+
|
|
|
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
+ spinlock_t irq_stats_lock;
|
|
|
+ struct dsi_irq_stats irq_stats;
|
|
|
+#endif
|
|
|
} dsi;
|
|
|
|
|
|
#ifdef DEBUG
|
|
@@ -528,6 +541,12 @@ void dsi_irq_handler(void)
|
|
|
|
|
|
irqstatus = dsi_read_reg(DSI_IRQSTATUS);
|
|
|
|
|
|
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
+ spin_lock(&dsi.irq_stats_lock);
|
|
|
+ dsi.irq_stats.irq_count++;
|
|
|
+ dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
|
|
|
+#endif
|
|
|
+
|
|
|
if (irqstatus & DSI_IRQ_ERROR_MASK) {
|
|
|
DSSERR("DSI error, irqstatus %x\n", irqstatus);
|
|
|
print_irq_status(irqstatus);
|
|
@@ -549,6 +568,10 @@ void dsi_irq_handler(void)
|
|
|
|
|
|
vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
|
|
|
|
|
|
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
+ dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
|
|
|
+#endif
|
|
|
+
|
|
|
if (vcstatus & DSI_VC_IRQ_BTA)
|
|
|
complete(&dsi.bta_completion);
|
|
|
|
|
@@ -568,6 +591,10 @@ void dsi_irq_handler(void)
|
|
|
if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
|
|
|
ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
|
|
|
|
|
|
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
+ dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
|
|
|
+#endif
|
|
|
+
|
|
|
dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
|
|
|
/* flush posted write */
|
|
|
dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
|
|
@@ -579,6 +606,10 @@ void dsi_irq_handler(void)
|
|
|
dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
|
|
|
/* flush posted write */
|
|
|
dsi_read_reg(DSI_IRQSTATUS);
|
|
|
+
|
|
|
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
+ spin_unlock(&dsi.irq_stats_lock);
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
|
|
@@ -797,12 +828,12 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
|
|
|
|
|
|
/* PLL_PWR_STATUS */
|
|
|
while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
|
|
|
- udelay(1);
|
|
|
- if (t++ > 1000) {
|
|
|
+ if (++t > 1000) {
|
|
|
DSSERR("Failed to set DSI PLL power mode to %d\n",
|
|
|
state);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
+ udelay(1);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -1226,6 +1257,95 @@ void dsi_dump_clocks(struct seq_file *s)
|
|
|
enable_clocks(0);
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
+void dsi_dump_irqs(struct seq_file *s)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ struct dsi_irq_stats stats;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&dsi.irq_stats_lock, flags);
|
|
|
+
|
|
|
+ stats = dsi.irq_stats;
|
|
|
+ memset(&dsi.irq_stats, 0, sizeof(dsi.irq_stats));
|
|
|
+ dsi.irq_stats.last_reset = jiffies;
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&dsi.irq_stats_lock, flags);
|
|
|
+
|
|
|
+ seq_printf(s, "period %u ms\n",
|
|
|
+ jiffies_to_msecs(jiffies - stats.last_reset));
|
|
|
+
|
|
|
+ seq_printf(s, "irqs %d\n", stats.irq_count);
|
|
|
+#define PIS(x) \
|
|
|
+ seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
|
|
|
+
|
|
|
+ seq_printf(s, "-- DSI interrupts --\n");
|
|
|
+ PIS(VC0);
|
|
|
+ PIS(VC1);
|
|
|
+ PIS(VC2);
|
|
|
+ PIS(VC3);
|
|
|
+ PIS(WAKEUP);
|
|
|
+ PIS(RESYNC);
|
|
|
+ PIS(PLL_LOCK);
|
|
|
+ PIS(PLL_UNLOCK);
|
|
|
+ PIS(PLL_RECALL);
|
|
|
+ PIS(COMPLEXIO_ERR);
|
|
|
+ PIS(HS_TX_TIMEOUT);
|
|
|
+ PIS(LP_RX_TIMEOUT);
|
|
|
+ PIS(TE_TRIGGER);
|
|
|
+ PIS(ACK_TRIGGER);
|
|
|
+ PIS(SYNC_LOST);
|
|
|
+ PIS(LDO_POWER_GOOD);
|
|
|
+ PIS(TA_TIMEOUT);
|
|
|
+#undef PIS
|
|
|
+
|
|
|
+#define PIS(x) \
|
|
|
+ seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
|
|
|
+ stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
|
|
|
+ stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
|
|
|
+ stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
|
|
|
+ stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
|
|
|
+
|
|
|
+ seq_printf(s, "-- VC interrupts --\n");
|
|
|
+ PIS(CS);
|
|
|
+ PIS(ECC_CORR);
|
|
|
+ PIS(PACKET_SENT);
|
|
|
+ PIS(FIFO_TX_OVF);
|
|
|
+ PIS(FIFO_RX_OVF);
|
|
|
+ PIS(BTA);
|
|
|
+ PIS(ECC_NO_CORR);
|
|
|
+ PIS(FIFO_TX_UDF);
|
|
|
+ PIS(PP_BUSY_CHANGE);
|
|
|
+#undef PIS
|
|
|
+
|
|
|
+#define PIS(x) \
|
|
|
+ seq_printf(s, "%-20s %10d\n", #x, \
|
|
|
+ stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
|
|
|
+
|
|
|
+ seq_printf(s, "-- CIO interrupts --\n");
|
|
|
+ PIS(ERRSYNCESC1);
|
|
|
+ PIS(ERRSYNCESC2);
|
|
|
+ PIS(ERRSYNCESC3);
|
|
|
+ PIS(ERRESC1);
|
|
|
+ PIS(ERRESC2);
|
|
|
+ PIS(ERRESC3);
|
|
|
+ PIS(ERRCONTROL1);
|
|
|
+ PIS(ERRCONTROL2);
|
|
|
+ PIS(ERRCONTROL3);
|
|
|
+ PIS(STATEULPS1);
|
|
|
+ PIS(STATEULPS2);
|
|
|
+ PIS(STATEULPS3);
|
|
|
+ PIS(ERRCONTENTIONLP0_1);
|
|
|
+ PIS(ERRCONTENTIONLP1_1);
|
|
|
+ PIS(ERRCONTENTIONLP0_2);
|
|
|
+ PIS(ERRCONTENTIONLP1_2);
|
|
|
+ PIS(ERRCONTENTIONLP0_3);
|
|
|
+ PIS(ERRCONTENTIONLP1_3);
|
|
|
+ PIS(ULPSACTIVENOT_ALL0);
|
|
|
+ PIS(ULPSACTIVENOT_ALL1);
|
|
|
+#undef PIS
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
void dsi_dump_regs(struct seq_file *s)
|
|
|
{
|
|
|
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
|
|
@@ -1321,12 +1441,12 @@ static int dsi_complexio_power(enum dsi_complexio_power_state state)
|
|
|
|
|
|
/* PWR_STATUS */
|
|
|
while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
|
|
|
- udelay(1);
|
|
|
- if (t++ > 1000) {
|
|
|
+ if (++t > 1000) {
|
|
|
DSSERR("failed to set complexio power state to "
|
|
|
"%d\n", state);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
+ udelay(1);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -1526,10 +1646,10 @@ static void dsi_complexio_uninit(void)
|
|
|
|
|
|
static int _dsi_wait_reset(void)
|
|
|
{
|
|
|
- int i = 0;
|
|
|
+ int t = 0;
|
|
|
|
|
|
while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
|
|
|
- if (i++ > 5) {
|
|
|
+ if (++t > 5) {
|
|
|
DSSERR("soft reset failed\n");
|
|
|
return -ENODEV;
|
|
|
}
|
|
@@ -1999,7 +2119,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- data_id = data_type | channel << 6;
|
|
|
+ data_id = data_type | dsi.vc[channel].dest_per << 6;
|
|
|
|
|
|
r = (data_id << 0) | (data << 8) | (ecc << 24);
|
|
|
|
|
@@ -2011,7 +2131,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
|
|
|
int dsi_vc_send_null(int channel)
|
|
|
{
|
|
|
u8 nullpkg[] = {0, 0, 0, 0};
|
|
|
- return dsi_vc_send_long(0, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
|
|
|
+ return dsi_vc_send_long(channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
|
|
|
}
|
|
|
EXPORT_SYMBOL(dsi_vc_send_null);
|
|
|
|
|
@@ -2058,7 +2178,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
|
|
|
int r;
|
|
|
|
|
|
if (dsi.debug_read)
|
|
|
- DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %u)\n", channel, dcs_cmd);
|
|
|
+ DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
|
|
|
|
|
|
r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
|
|
|
if (r)
|
|
@@ -2586,7 +2706,6 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
|
|
|
/* using fifo not empty */
|
|
|
/* TX_FIFO_NOT_EMPTY */
|
|
|
while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
|
|
|
- udelay(1);
|
|
|
fifo_stalls++;
|
|
|
if (fifo_stalls > 0xfffff) {
|
|
|
DSSERR("fifo stalls overflow, pixels left %d\n",
|
|
@@ -2594,6 +2713,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
|
|
|
dsi_if_enable(0);
|
|
|
return -EIO;
|
|
|
}
|
|
|
+ udelay(1);
|
|
|
}
|
|
|
#elif 1
|
|
|
/* using fifo emptiness */
|
|
@@ -2812,11 +2932,15 @@ static int dsi_set_update_mode(struct omap_dss_device *dssdev,
|
|
|
|
|
|
static int dsi_set_te(struct omap_dss_device *dssdev, bool enable)
|
|
|
{
|
|
|
- int r;
|
|
|
- r = dssdev->driver->enable_te(dssdev, enable);
|
|
|
- /* XXX for some reason, DSI TE breaks if we don't wait here.
|
|
|
- * Panel bug? Needs more studying */
|
|
|
- msleep(100);
|
|
|
+ int r = 0;
|
|
|
+
|
|
|
+ if (dssdev->driver->enable_te) {
|
|
|
+ r = dssdev->driver->enable_te(dssdev, enable);
|
|
|
+ /* XXX for some reason, DSI TE breaks if we don't wait here.
|
|
|
+ * Panel bug? Needs more studying */
|
|
|
+ msleep(100);
|
|
|
+ }
|
|
|
+
|
|
|
return r;
|
|
|
}
|
|
|
|
|
@@ -3637,6 +3761,11 @@ int dsi_init(struct platform_device *pdev)
|
|
|
spin_lock_init(&dsi.errors_lock);
|
|
|
dsi.errors = 0;
|
|
|
|
|
|
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
+ spin_lock_init(&dsi.irq_stats_lock);
|
|
|
+ dsi.irq_stats.last_reset = jiffies;
|
|
|
+#endif
|
|
|
+
|
|
|
init_completion(&dsi.bta_completion);
|
|
|
init_completion(&dsi.update_completion);
|
|
|
|