|
@@ -33,7 +33,6 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/workqueue.h>
|
|
|
#include <linux/hardirq.h>
|
|
|
-#include <linux/interrupt.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/pm_runtime.h>
|
|
|
#include <linux/sizes.h>
|
|
@@ -47,21 +46,6 @@
|
|
|
/* DISPC */
|
|
|
#define DISPC_SZ_REGS SZ_4K
|
|
|
|
|
|
-#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
|
|
|
- DISPC_IRQ_OCP_ERR | \
|
|
|
- DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
|
|
|
- DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
|
|
|
- DISPC_IRQ_SYNC_LOST | \
|
|
|
- DISPC_IRQ_SYNC_LOST_DIGIT)
|
|
|
-
|
|
|
-#define DISPC_MAX_NR_ISRS 8
|
|
|
-
|
|
|
-struct omap_dispc_isr_data {
|
|
|
- omap_dispc_isr_t isr;
|
|
|
- void *arg;
|
|
|
- u32 mask;
|
|
|
-};
|
|
|
-
|
|
|
enum omap_burst_size {
|
|
|
BURST_SIZE_X2 = 0,
|
|
|
BURST_SIZE_X4 = 1,
|
|
@@ -74,12 +58,6 @@ enum omap_burst_size {
|
|
|
#define REG_FLD_MOD(idx, val, start, end) \
|
|
|
dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
|
|
|
|
|
|
-struct dispc_irq_stats {
|
|
|
- unsigned long last_reset;
|
|
|
- unsigned irq_count;
|
|
|
- unsigned irqs[32];
|
|
|
-};
|
|
|
-
|
|
|
struct dispc_features {
|
|
|
u8 sw_start;
|
|
|
u8 fp_start;
|
|
@@ -124,21 +102,10 @@ static struct {
|
|
|
/* maps which plane is using a fifo. fifo-id -> plane-id */
|
|
|
int fifo_assignment[DISPC_MAX_NR_FIFOS];
|
|
|
|
|
|
- spinlock_t irq_lock;
|
|
|
- u32 irq_error_mask;
|
|
|
- struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
|
|
|
- u32 error_irqs;
|
|
|
- struct work_struct error_work;
|
|
|
-
|
|
|
bool ctx_valid;
|
|
|
u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
|
|
|
|
|
|
const struct dispc_features *feat;
|
|
|
-
|
|
|
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
- spinlock_t irq_stats_lock;
|
|
|
- struct dispc_irq_stats irq_stats;
|
|
|
-#endif
|
|
|
} dispc;
|
|
|
|
|
|
enum omap_color_component {
|
|
@@ -249,7 +216,6 @@ struct color_conv_coef {
|
|
|
int full_range;
|
|
|
};
|
|
|
|
|
|
-static void _omap_dispc_set_irqs(void);
|
|
|
static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
|
|
|
static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
|
|
|
|
|
@@ -528,6 +494,7 @@ int dispc_runtime_get(void)
|
|
|
WARN_ON(r < 0);
|
|
|
return r < 0 ? r : 0;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_runtime_get);
|
|
|
|
|
|
void dispc_runtime_put(void)
|
|
|
{
|
|
@@ -538,11 +505,13 @@ void dispc_runtime_put(void)
|
|
|
r = pm_runtime_put_sync(&dispc.pdev->dev);
|
|
|
WARN_ON(r < 0 && r != -ENOSYS);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_runtime_put);
|
|
|
|
|
|
u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
|
|
|
{
|
|
|
return mgr_desc[channel].vsync_irq;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_get_vsync_irq);
|
|
|
|
|
|
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
|
|
|
{
|
|
@@ -551,11 +520,13 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
|
|
|
|
|
|
return mgr_desc[channel].framedone_irq;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_get_framedone_irq);
|
|
|
|
|
|
u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel)
|
|
|
{
|
|
|
return mgr_desc[channel].sync_lost_irq;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq);
|
|
|
|
|
|
u32 dispc_wb_get_framedone_irq(void)
|
|
|
{
|
|
@@ -566,6 +537,7 @@ bool dispc_mgr_go_busy(enum omap_channel channel)
|
|
|
{
|
|
|
return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_go_busy);
|
|
|
|
|
|
void dispc_mgr_go(enum omap_channel channel)
|
|
|
{
|
|
@@ -576,6 +548,7 @@ void dispc_mgr_go(enum omap_channel channel)
|
|
|
|
|
|
mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_go);
|
|
|
|
|
|
bool dispc_wb_go_busy(void)
|
|
|
{
|
|
@@ -979,6 +952,7 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
|
|
|
}
|
|
|
dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_ovl_set_channel_out);
|
|
|
|
|
|
static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
|
|
|
{
|
|
@@ -2354,6 +2328,47 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
|
|
|
+ const struct omap_overlay_info *oi,
|
|
|
+ const struct omap_video_timings *timings,
|
|
|
+ int *x_predecim, int *y_predecim)
|
|
|
+{
|
|
|
+ enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
|
|
|
+ bool five_taps = true;
|
|
|
+ bool fieldmode = 0;
|
|
|
+ u16 in_height = oi->height;
|
|
|
+ u16 in_width = oi->width;
|
|
|
+ bool ilace = timings->interlace;
|
|
|
+ u16 out_width, out_height;
|
|
|
+ int pos_x = oi->pos_x;
|
|
|
+ unsigned long pclk = dispc_mgr_pclk_rate(channel);
|
|
|
+ unsigned long lclk = dispc_mgr_lclk_rate(channel);
|
|
|
+
|
|
|
+ out_width = oi->out_width == 0 ? oi->width : oi->out_width;
|
|
|
+ out_height = oi->out_height == 0 ? oi->height : oi->out_height;
|
|
|
+
|
|
|
+ if (ilace && oi->height == out_height)
|
|
|
+ fieldmode = 1;
|
|
|
+
|
|
|
+ if (ilace) {
|
|
|
+ if (fieldmode)
|
|
|
+ in_height /= 2;
|
|
|
+ out_height /= 2;
|
|
|
+
|
|
|
+ DSSDBG("adjusting for ilace: height %d, out_height %d\n",
|
|
|
+ in_height, out_height);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!dss_feat_color_mode_supported(plane, oi->color_mode))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width,
|
|
|
+ in_height, out_width, out_height, oi->color_mode,
|
|
|
+ &five_taps, x_predecim, y_predecim, pos_x,
|
|
|
+ oi->rotation_type, false);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dispc_ovl_check);
|
|
|
+
|
|
|
static int dispc_ovl_setup_common(enum omap_plane plane,
|
|
|
enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
|
|
|
u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
|
|
@@ -2533,6 +2548,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
|
|
|
|
|
|
return r;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_ovl_setup);
|
|
|
|
|
|
int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
|
|
|
bool mem_to_mem, const struct omap_video_timings *mgr_timings)
|
|
@@ -2593,17 +2609,13 @@ int dispc_ovl_enable(enum omap_plane plane, bool enable)
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_ovl_enable);
|
|
|
|
|
|
bool dispc_ovl_enabled(enum omap_plane plane)
|
|
|
{
|
|
|
return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
|
|
|
}
|
|
|
-
|
|
|
-static void dispc_mgr_disable_isr(void *data, u32 mask)
|
|
|
-{
|
|
|
- struct completion *compl = data;
|
|
|
- complete(compl);
|
|
|
-}
|
|
|
+EXPORT_SYMBOL(dispc_ovl_enabled);
|
|
|
|
|
|
void dispc_mgr_enable(enum omap_channel channel, bool enable)
|
|
|
{
|
|
@@ -2611,180 +2623,13 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable)
|
|
|
/* flush posted write */
|
|
|
mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_enable);
|
|
|
|
|
|
bool dispc_mgr_is_enabled(enum omap_channel channel)
|
|
|
{
|
|
|
return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
|
|
|
}
|
|
|
-
|
|
|
-static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
|
|
|
-{
|
|
|
- dispc_mgr_enable(channel, true);
|
|
|
-}
|
|
|
-
|
|
|
-static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
|
|
|
-{
|
|
|
- DECLARE_COMPLETION_ONSTACK(framedone_compl);
|
|
|
- int r;
|
|
|
- u32 irq;
|
|
|
-
|
|
|
- if (dispc_mgr_is_enabled(channel) == false)
|
|
|
- return;
|
|
|
-
|
|
|
- /*
|
|
|
- * When we disable LCD output, we need to wait for FRAMEDONE to know
|
|
|
- * that DISPC has finished with the LCD output.
|
|
|
- */
|
|
|
-
|
|
|
- irq = dispc_mgr_get_framedone_irq(channel);
|
|
|
-
|
|
|
- r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
|
|
|
- irq);
|
|
|
- if (r)
|
|
|
- DSSERR("failed to register FRAMEDONE isr\n");
|
|
|
-
|
|
|
- dispc_mgr_enable(channel, false);
|
|
|
-
|
|
|
- /* if we couldn't register for framedone, just sleep and exit */
|
|
|
- if (r) {
|
|
|
- msleep(100);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!wait_for_completion_timeout(&framedone_compl,
|
|
|
- msecs_to_jiffies(100)))
|
|
|
- DSSERR("timeout waiting for FRAME DONE\n");
|
|
|
-
|
|
|
- r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
|
|
|
- irq);
|
|
|
- if (r)
|
|
|
- DSSERR("failed to unregister FRAMEDONE isr\n");
|
|
|
-}
|
|
|
-
|
|
|
-static void dispc_digit_out_enable_isr(void *data, u32 mask)
|
|
|
-{
|
|
|
- struct completion *compl = data;
|
|
|
-
|
|
|
- /* ignore any sync lost interrupts */
|
|
|
- if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
|
|
|
- complete(compl);
|
|
|
-}
|
|
|
-
|
|
|
-static void dispc_mgr_enable_digit_out(void)
|
|
|
-{
|
|
|
- DECLARE_COMPLETION_ONSTACK(vsync_compl);
|
|
|
- int r;
|
|
|
- u32 irq_mask;
|
|
|
-
|
|
|
- if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true)
|
|
|
- return;
|
|
|
-
|
|
|
- /*
|
|
|
- * Digit output produces some sync lost interrupts during the first
|
|
|
- * frame when enabling. Those need to be ignored, so we register for the
|
|
|
- * sync lost irq to prevent the error handler from triggering.
|
|
|
- */
|
|
|
-
|
|
|
- irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
|
|
|
- dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
|
|
|
-
|
|
|
- r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
|
|
|
- irq_mask);
|
|
|
- if (r) {
|
|
|
- DSSERR("failed to register %x isr\n", irq_mask);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
|
|
|
-
|
|
|
- /* wait for the first evsync */
|
|
|
- if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
|
|
|
- DSSERR("timeout waiting for digit out to start\n");
|
|
|
-
|
|
|
- r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
|
|
|
- irq_mask);
|
|
|
- if (r)
|
|
|
- DSSERR("failed to unregister %x isr\n", irq_mask);
|
|
|
-}
|
|
|
-
|
|
|
-static void dispc_mgr_disable_digit_out(void)
|
|
|
-{
|
|
|
- DECLARE_COMPLETION_ONSTACK(framedone_compl);
|
|
|
- int r, i;
|
|
|
- u32 irq_mask;
|
|
|
- int num_irqs;
|
|
|
-
|
|
|
- if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false)
|
|
|
- return;
|
|
|
-
|
|
|
- /*
|
|
|
- * When we disable the digit output, we need to wait for FRAMEDONE to
|
|
|
- * know that DISPC has finished with the output.
|
|
|
- */
|
|
|
-
|
|
|
- irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
|
|
|
- num_irqs = 1;
|
|
|
-
|
|
|
- if (!irq_mask) {
|
|
|
- /*
|
|
|
- * omap 2/3 don't have framedone irq for TV, so we need to use
|
|
|
- * vsyncs for this.
|
|
|
- */
|
|
|
-
|
|
|
- irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
|
|
|
- /*
|
|
|
- * We need to wait for both even and odd vsyncs. Note that this
|
|
|
- * is not totally reliable, as we could get a vsync interrupt
|
|
|
- * before we disable the output, which leads to timeout in the
|
|
|
- * wait_for_completion.
|
|
|
- */
|
|
|
- num_irqs = 2;
|
|
|
- }
|
|
|
-
|
|
|
- r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
|
|
|
- irq_mask);
|
|
|
- if (r)
|
|
|
- DSSERR("failed to register %x isr\n", irq_mask);
|
|
|
-
|
|
|
- dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
|
|
|
-
|
|
|
- /* if we couldn't register the irq, just sleep and exit */
|
|
|
- if (r) {
|
|
|
- msleep(100);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < num_irqs; ++i) {
|
|
|
- if (!wait_for_completion_timeout(&framedone_compl,
|
|
|
- msecs_to_jiffies(100)))
|
|
|
- DSSERR("timeout waiting for digit out to stop\n");
|
|
|
- }
|
|
|
-
|
|
|
- r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
|
|
|
- irq_mask);
|
|
|
- if (r)
|
|
|
- DSSERR("failed to unregister %x isr\n", irq_mask);
|
|
|
-}
|
|
|
-
|
|
|
-void dispc_mgr_enable_sync(enum omap_channel channel)
|
|
|
-{
|
|
|
- if (dss_mgr_is_lcd(channel))
|
|
|
- dispc_mgr_enable_lcd_out(channel);
|
|
|
- else if (channel == OMAP_DSS_CHANNEL_DIGIT)
|
|
|
- dispc_mgr_enable_digit_out();
|
|
|
- else
|
|
|
- WARN_ON(1);
|
|
|
-}
|
|
|
-
|
|
|
-void dispc_mgr_disable_sync(enum omap_channel channel)
|
|
|
-{
|
|
|
- if (dss_mgr_is_lcd(channel))
|
|
|
- dispc_mgr_disable_lcd_out(channel);
|
|
|
- else if (channel == OMAP_DSS_CHANNEL_DIGIT)
|
|
|
- dispc_mgr_disable_digit_out();
|
|
|
- else
|
|
|
- WARN_ON(1);
|
|
|
-}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_is_enabled);
|
|
|
|
|
|
void dispc_wb_enable(bool enable)
|
|
|
{
|
|
@@ -2881,6 +2726,7 @@ void dispc_mgr_setup(enum omap_channel channel,
|
|
|
dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
|
|
|
}
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_setup);
|
|
|
|
|
|
static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
|
|
|
{
|
|
@@ -2957,6 +2803,7 @@ void dispc_mgr_set_lcd_config(enum omap_channel channel,
|
|
|
|
|
|
dispc_mgr_set_lcd_type_tft(channel);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_set_lcd_config);
|
|
|
|
|
|
static bool _dispc_mgr_size_ok(u16 width, u16 height)
|
|
|
{
|
|
@@ -3095,6 +2942,7 @@ void dispc_mgr_set_timings(enum omap_channel channel,
|
|
|
|
|
|
dispc_mgr_set_size(channel, t.x_res, t.y_res);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_mgr_set_timings);
|
|
|
|
|
|
static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
|
|
|
u16 pck_div)
|
|
@@ -3301,64 +3149,6 @@ void dispc_dump_clocks(struct seq_file *s)
|
|
|
dispc_runtime_put();
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
-static void dispc_dump_irqs(struct seq_file *s)
|
|
|
-{
|
|
|
- unsigned long flags;
|
|
|
- struct dispc_irq_stats stats;
|
|
|
-
|
|
|
- spin_lock_irqsave(&dispc.irq_stats_lock, flags);
|
|
|
-
|
|
|
- stats = dispc.irq_stats;
|
|
|
- memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
|
|
|
- dispc.irq_stats.last_reset = jiffies;
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&dispc.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.irqs[ffs(DISPC_IRQ_##x)-1]);
|
|
|
-
|
|
|
- PIS(FRAMEDONE);
|
|
|
- PIS(VSYNC);
|
|
|
- PIS(EVSYNC_EVEN);
|
|
|
- PIS(EVSYNC_ODD);
|
|
|
- PIS(ACBIAS_COUNT_STAT);
|
|
|
- PIS(PROG_LINE_NUM);
|
|
|
- PIS(GFX_FIFO_UNDERFLOW);
|
|
|
- PIS(GFX_END_WIN);
|
|
|
- PIS(PAL_GAMMA_MASK);
|
|
|
- PIS(OCP_ERR);
|
|
|
- PIS(VID1_FIFO_UNDERFLOW);
|
|
|
- PIS(VID1_END_WIN);
|
|
|
- PIS(VID2_FIFO_UNDERFLOW);
|
|
|
- PIS(VID2_END_WIN);
|
|
|
- if (dss_feat_get_num_ovls() > 3) {
|
|
|
- PIS(VID3_FIFO_UNDERFLOW);
|
|
|
- PIS(VID3_END_WIN);
|
|
|
- }
|
|
|
- PIS(SYNC_LOST);
|
|
|
- PIS(SYNC_LOST_DIGIT);
|
|
|
- PIS(WAKEUP);
|
|
|
- if (dss_has_feature(FEAT_MGR_LCD2)) {
|
|
|
- PIS(FRAMEDONE2);
|
|
|
- PIS(VSYNC2);
|
|
|
- PIS(ACBIAS_COUNT_STAT2);
|
|
|
- PIS(SYNC_LOST2);
|
|
|
- }
|
|
|
- if (dss_has_feature(FEAT_MGR_LCD3)) {
|
|
|
- PIS(FRAMEDONE3);
|
|
|
- PIS(VSYNC3);
|
|
|
- PIS(ACBIAS_COUNT_STAT3);
|
|
|
- PIS(SYNC_LOST3);
|
|
|
- }
|
|
|
-#undef PIS
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
static void dispc_dump_regs(struct seq_file *s)
|
|
|
{
|
|
|
int i, j;
|
|
@@ -3616,16 +3406,19 @@ u32 dispc_read_irqstatus(void)
|
|
|
{
|
|
|
return dispc_read_reg(DISPC_IRQSTATUS);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_read_irqstatus);
|
|
|
|
|
|
void dispc_clear_irqstatus(u32 mask)
|
|
|
{
|
|
|
dispc_write_reg(DISPC_IRQSTATUS, mask);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_clear_irqstatus);
|
|
|
|
|
|
u32 dispc_read_irqenable(void)
|
|
|
{
|
|
|
return dispc_read_reg(DISPC_IRQENABLE);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(dispc_read_irqenable);
|
|
|
|
|
|
void dispc_write_irqenable(u32 mask)
|
|
|
{
|
|
@@ -3636,376 +3429,7 @@ void dispc_write_irqenable(u32 mask)
|
|
|
|
|
|
dispc_write_reg(DISPC_IRQENABLE, mask);
|
|
|
}
|
|
|
-
|
|
|
-/* dispc.irq_lock has to be locked by the caller */
|
|
|
-static void _omap_dispc_set_irqs(void)
|
|
|
-{
|
|
|
- u32 mask;
|
|
|
- int i;
|
|
|
- struct omap_dispc_isr_data *isr_data;
|
|
|
-
|
|
|
- mask = dispc.irq_error_mask;
|
|
|
-
|
|
|
- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
|
|
- isr_data = &dispc.registered_isr[i];
|
|
|
-
|
|
|
- if (isr_data->isr == NULL)
|
|
|
- continue;
|
|
|
-
|
|
|
- mask |= isr_data->mask;
|
|
|
- }
|
|
|
-
|
|
|
- dispc_write_irqenable(mask);
|
|
|
-}
|
|
|
-
|
|
|
-int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
|
|
|
-{
|
|
|
- int i;
|
|
|
- int ret;
|
|
|
- unsigned long flags;
|
|
|
- struct omap_dispc_isr_data *isr_data;
|
|
|
-
|
|
|
- if (isr == NULL)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- spin_lock_irqsave(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- /* check for duplicate entry */
|
|
|
- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
|
|
- isr_data = &dispc.registered_isr[i];
|
|
|
- if (isr_data->isr == isr && isr_data->arg == arg &&
|
|
|
- isr_data->mask == mask) {
|
|
|
- ret = -EINVAL;
|
|
|
- goto err;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- isr_data = NULL;
|
|
|
- ret = -EBUSY;
|
|
|
-
|
|
|
- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
|
|
- isr_data = &dispc.registered_isr[i];
|
|
|
-
|
|
|
- if (isr_data->isr != NULL)
|
|
|
- continue;
|
|
|
-
|
|
|
- isr_data->isr = isr;
|
|
|
- isr_data->arg = arg;
|
|
|
- isr_data->mask = mask;
|
|
|
- ret = 0;
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (ret)
|
|
|
- goto err;
|
|
|
-
|
|
|
- _omap_dispc_set_irqs();
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- return 0;
|
|
|
-err:
|
|
|
- spin_unlock_irqrestore(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(omap_dispc_register_isr);
|
|
|
-
|
|
|
-int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
|
|
|
-{
|
|
|
- int i;
|
|
|
- unsigned long flags;
|
|
|
- int ret = -EINVAL;
|
|
|
- struct omap_dispc_isr_data *isr_data;
|
|
|
-
|
|
|
- spin_lock_irqsave(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
|
|
- isr_data = &dispc.registered_isr[i];
|
|
|
- if (isr_data->isr != isr || isr_data->arg != arg ||
|
|
|
- isr_data->mask != mask)
|
|
|
- continue;
|
|
|
-
|
|
|
- /* found the correct isr */
|
|
|
-
|
|
|
- isr_data->isr = NULL;
|
|
|
- isr_data->arg = NULL;
|
|
|
- isr_data->mask = 0;
|
|
|
-
|
|
|
- ret = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (ret == 0)
|
|
|
- _omap_dispc_set_irqs();
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(omap_dispc_unregister_isr);
|
|
|
-
|
|
|
-static void print_irq_status(u32 status)
|
|
|
-{
|
|
|
- if ((status & dispc.irq_error_mask) == 0)
|
|
|
- return;
|
|
|
-
|
|
|
-#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
|
|
|
-
|
|
|
- pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
|
|
|
- status,
|
|
|
- PIS(OCP_ERR),
|
|
|
- PIS(GFX_FIFO_UNDERFLOW),
|
|
|
- PIS(VID1_FIFO_UNDERFLOW),
|
|
|
- PIS(VID2_FIFO_UNDERFLOW),
|
|
|
- dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
|
|
|
- PIS(SYNC_LOST),
|
|
|
- PIS(SYNC_LOST_DIGIT),
|
|
|
- dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
|
|
|
- dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
|
|
|
-#undef PIS
|
|
|
-}
|
|
|
-
|
|
|
-/* Called from dss.c. Note that we don't touch clocks here,
|
|
|
- * but we presume they are on because we got an IRQ. However,
|
|
|
- * an irq handler may turn the clocks off, so we may not have
|
|
|
- * clock later in the function. */
|
|
|
-static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
|
|
|
-{
|
|
|
- int i;
|
|
|
- u32 irqstatus, irqenable;
|
|
|
- u32 handledirqs = 0;
|
|
|
- u32 unhandled_errors;
|
|
|
- struct omap_dispc_isr_data *isr_data;
|
|
|
- struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
|
|
|
-
|
|
|
- spin_lock(&dispc.irq_lock);
|
|
|
-
|
|
|
- irqstatus = dispc_read_irqstatus();
|
|
|
- irqenable = dispc_read_irqenable();
|
|
|
-
|
|
|
- /* IRQ is not for us */
|
|
|
- if (!(irqstatus & irqenable)) {
|
|
|
- spin_unlock(&dispc.irq_lock);
|
|
|
- return IRQ_NONE;
|
|
|
- }
|
|
|
-
|
|
|
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
- spin_lock(&dispc.irq_stats_lock);
|
|
|
- dispc.irq_stats.irq_count++;
|
|
|
- dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
|
|
|
- spin_unlock(&dispc.irq_stats_lock);
|
|
|
-#endif
|
|
|
-
|
|
|
- print_irq_status(irqstatus);
|
|
|
-
|
|
|
- /* Ack the interrupt. Do it here before clocks are possibly turned
|
|
|
- * off */
|
|
|
- dispc_clear_irqstatus(irqstatus);
|
|
|
- /* flush posted write */
|
|
|
- dispc_read_irqstatus();
|
|
|
-
|
|
|
- /* make a copy and unlock, so that isrs can unregister
|
|
|
- * themselves */
|
|
|
- memcpy(registered_isr, dispc.registered_isr,
|
|
|
- sizeof(registered_isr));
|
|
|
-
|
|
|
- spin_unlock(&dispc.irq_lock);
|
|
|
-
|
|
|
- for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
|
|
- isr_data = ®istered_isr[i];
|
|
|
-
|
|
|
- if (!isr_data->isr)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (isr_data->mask & irqstatus) {
|
|
|
- isr_data->isr(isr_data->arg, irqstatus);
|
|
|
- handledirqs |= isr_data->mask;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- spin_lock(&dispc.irq_lock);
|
|
|
-
|
|
|
- unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
|
|
|
-
|
|
|
- if (unhandled_errors) {
|
|
|
- dispc.error_irqs |= unhandled_errors;
|
|
|
-
|
|
|
- dispc.irq_error_mask &= ~unhandled_errors;
|
|
|
- _omap_dispc_set_irqs();
|
|
|
-
|
|
|
- schedule_work(&dispc.error_work);
|
|
|
- }
|
|
|
-
|
|
|
- spin_unlock(&dispc.irq_lock);
|
|
|
-
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
-static void dispc_error_worker(struct work_struct *work)
|
|
|
-{
|
|
|
- int i;
|
|
|
- u32 errors;
|
|
|
- unsigned long flags;
|
|
|
- static const unsigned fifo_underflow_bits[] = {
|
|
|
- DISPC_IRQ_GFX_FIFO_UNDERFLOW,
|
|
|
- DISPC_IRQ_VID1_FIFO_UNDERFLOW,
|
|
|
- DISPC_IRQ_VID2_FIFO_UNDERFLOW,
|
|
|
- DISPC_IRQ_VID3_FIFO_UNDERFLOW,
|
|
|
- };
|
|
|
-
|
|
|
- spin_lock_irqsave(&dispc.irq_lock, flags);
|
|
|
- errors = dispc.error_irqs;
|
|
|
- dispc.error_irqs = 0;
|
|
|
- spin_unlock_irqrestore(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- dispc_runtime_get();
|
|
|
-
|
|
|
- for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
|
|
|
- struct omap_overlay *ovl;
|
|
|
- unsigned bit;
|
|
|
-
|
|
|
- ovl = omap_dss_get_overlay(i);
|
|
|
- bit = fifo_underflow_bits[i];
|
|
|
-
|
|
|
- if (bit & errors) {
|
|
|
- DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
|
|
|
- ovl->name);
|
|
|
- dispc_ovl_enable(ovl->id, false);
|
|
|
- dispc_mgr_go(ovl->manager->id);
|
|
|
- msleep(50);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
|
|
- struct omap_overlay_manager *mgr;
|
|
|
- unsigned bit;
|
|
|
-
|
|
|
- mgr = omap_dss_get_overlay_manager(i);
|
|
|
- bit = mgr_desc[i].sync_lost_irq;
|
|
|
-
|
|
|
- if (bit & errors) {
|
|
|
- int j;
|
|
|
-
|
|
|
- DSSERR("SYNC_LOST on channel %s, restarting the output "
|
|
|
- "with video overlays disabled\n",
|
|
|
- mgr->name);
|
|
|
-
|
|
|
- dss_mgr_disable(mgr);
|
|
|
-
|
|
|
- for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
|
|
|
- struct omap_overlay *ovl;
|
|
|
- ovl = omap_dss_get_overlay(j);
|
|
|
-
|
|
|
- if (ovl->id != OMAP_DSS_GFX &&
|
|
|
- ovl->manager == mgr)
|
|
|
- ovl->disable(ovl);
|
|
|
- }
|
|
|
-
|
|
|
- dss_mgr_enable(mgr);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (errors & DISPC_IRQ_OCP_ERR) {
|
|
|
- DSSERR("OCP_ERR\n");
|
|
|
- for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
|
|
- struct omap_overlay_manager *mgr;
|
|
|
-
|
|
|
- mgr = omap_dss_get_overlay_manager(i);
|
|
|
- dss_mgr_disable(mgr);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- spin_lock_irqsave(&dispc.irq_lock, flags);
|
|
|
- dispc.irq_error_mask |= errors;
|
|
|
- _omap_dispc_set_irqs();
|
|
|
- spin_unlock_irqrestore(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- dispc_runtime_put();
|
|
|
-}
|
|
|
-
|
|
|
-int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
|
|
|
-{
|
|
|
- void dispc_irq_wait_handler(void *data, u32 mask)
|
|
|
- {
|
|
|
- complete((struct completion *)data);
|
|
|
- }
|
|
|
-
|
|
|
- int r;
|
|
|
- DECLARE_COMPLETION_ONSTACK(completion);
|
|
|
-
|
|
|
- r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
|
|
|
- irqmask);
|
|
|
-
|
|
|
- if (r)
|
|
|
- return r;
|
|
|
-
|
|
|
- timeout = wait_for_completion_timeout(&completion, timeout);
|
|
|
-
|
|
|
- omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
|
|
|
-
|
|
|
- if (timeout == 0)
|
|
|
- return -ETIMEDOUT;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
|
|
|
- unsigned long timeout)
|
|
|
-{
|
|
|
- void dispc_irq_wait_handler(void *data, u32 mask)
|
|
|
- {
|
|
|
- complete((struct completion *)data);
|
|
|
- }
|
|
|
-
|
|
|
- int r;
|
|
|
- DECLARE_COMPLETION_ONSTACK(completion);
|
|
|
-
|
|
|
- r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
|
|
|
- irqmask);
|
|
|
-
|
|
|
- if (r)
|
|
|
- return r;
|
|
|
-
|
|
|
- timeout = wait_for_completion_interruptible_timeout(&completion,
|
|
|
- timeout);
|
|
|
-
|
|
|
- omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
|
|
|
-
|
|
|
- if (timeout == 0)
|
|
|
- return -ETIMEDOUT;
|
|
|
-
|
|
|
- if (timeout == -ERESTARTSYS)
|
|
|
- return -ERESTARTSYS;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void _omap_dispc_initialize_irq(void)
|
|
|
-{
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- spin_lock_irqsave(&dispc.irq_lock, flags);
|
|
|
-
|
|
|
- memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
|
|
|
-
|
|
|
- dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
|
|
|
- if (dss_has_feature(FEAT_MGR_LCD2))
|
|
|
- dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
|
|
|
- if (dss_has_feature(FEAT_MGR_LCD3))
|
|
|
- dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
|
|
|
- if (dss_feat_get_num_ovls() > 3)
|
|
|
- dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
|
|
|
-
|
|
|
- /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
|
|
|
- * so clear it */
|
|
|
- dispc_clear_irqstatus(dispc_read_irqstatus());
|
|
|
-
|
|
|
- _omap_dispc_set_irqs();
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&dispc.irq_lock, flags);
|
|
|
-}
|
|
|
+EXPORT_SYMBOL(dispc_write_irqenable);
|
|
|
|
|
|
void dispc_enable_sidle(void)
|
|
|
{
|
|
@@ -4176,6 +3600,19 @@ static int __init dispc_init_features(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int dispc_request_irq(irq_handler_t handler, void *dev_id)
|
|
|
+{
|
|
|
+ return devm_request_irq(&dispc.pdev->dev, dispc.irq, handler,
|
|
|
+ IRQF_SHARED, "OMAP DISPC", dev_id);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dispc_request_irq);
|
|
|
+
|
|
|
+void dispc_free_irq(void *dev_id)
|
|
|
+{
|
|
|
+ devm_free_irq(&dispc.pdev->dev, dispc.irq, dev_id);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dispc_free_irq);
|
|
|
+
|
|
|
/* DISPC HW IP initialisation */
|
|
|
static int __init omap_dispchw_probe(struct platform_device *pdev)
|
|
|
{
|
|
@@ -4190,15 +3627,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
|
|
if (r)
|
|
|
return r;
|
|
|
|
|
|
- spin_lock_init(&dispc.irq_lock);
|
|
|
-
|
|
|
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
- spin_lock_init(&dispc.irq_stats_lock);
|
|
|
- dispc.irq_stats.last_reset = jiffies;
|
|
|
-#endif
|
|
|
-
|
|
|
- INIT_WORK(&dispc.error_work, dispc_error_worker);
|
|
|
-
|
|
|
dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
|
|
|
if (!dispc_mem) {
|
|
|
DSSERR("can't get IORESOURCE_MEM DISPC\n");
|
|
@@ -4218,13 +3646,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
- r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler,
|
|
|
- IRQF_SHARED, "OMAP DISPC", dispc.pdev);
|
|
|
- if (r < 0) {
|
|
|
- DSSERR("request_irq failed\n");
|
|
|
- return r;
|
|
|
- }
|
|
|
-
|
|
|
clk = clk_get(&pdev->dev, "fck");
|
|
|
if (IS_ERR(clk)) {
|
|
|
DSSERR("can't get fck\n");
|
|
@@ -4242,8 +3663,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
|
|
|
|
|
_omap_dispc_initial_config();
|
|
|
|
|
|
- _omap_dispc_initialize_irq();
|
|
|
-
|
|
|
rev = dispc_read_reg(DISPC_REVISION);
|
|
|
dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
|
|
|
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
|
@@ -4252,9 +3671,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
|
|
|
|
|
dss_debugfs_create_file("dispc", dispc_dump_regs);
|
|
|
|
|
|
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
|
|
- dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
|
|
|
-#endif
|
|
|
return 0;
|
|
|
|
|
|
err_runtime_get:
|