|
@@ -101,6 +101,8 @@ static struct {
|
|
void __iomem *base;
|
|
void __iomem *base;
|
|
|
|
|
|
int irq;
|
|
int irq;
|
|
|
|
+ irq_handler_t user_handler;
|
|
|
|
+ void *user_data;
|
|
|
|
|
|
unsigned long core_clk_rate;
|
|
unsigned long core_clk_rate;
|
|
unsigned long tv_pclk_rate;
|
|
unsigned long tv_pclk_rate;
|
|
@@ -113,6 +115,8 @@ static struct {
|
|
u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
|
|
u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
|
|
|
|
|
|
const struct dispc_features *feat;
|
|
const struct dispc_features *feat;
|
|
|
|
+
|
|
|
|
+ bool is_enabled;
|
|
} dispc;
|
|
} dispc;
|
|
|
|
|
|
enum omap_color_component {
|
|
enum omap_color_component {
|
|
@@ -141,12 +145,18 @@ enum mgr_reg_fields {
|
|
DISPC_MGR_FLD_NUM,
|
|
DISPC_MGR_FLD_NUM,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct dispc_reg_field {
|
|
|
|
+ u16 reg;
|
|
|
|
+ u8 high;
|
|
|
|
+ u8 low;
|
|
|
|
+};
|
|
|
|
+
|
|
static const struct {
|
|
static const struct {
|
|
const char *name;
|
|
const char *name;
|
|
u32 vsync_irq;
|
|
u32 vsync_irq;
|
|
u32 framedone_irq;
|
|
u32 framedone_irq;
|
|
u32 sync_lost_irq;
|
|
u32 sync_lost_irq;
|
|
- struct reg_field reg_desc[DISPC_MGR_FLD_NUM];
|
|
|
|
|
|
+ struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
|
|
} mgr_desc[] = {
|
|
} mgr_desc[] = {
|
|
[OMAP_DSS_CHANNEL_LCD] = {
|
|
[OMAP_DSS_CHANNEL_LCD] = {
|
|
.name = "LCD",
|
|
.name = "LCD",
|
|
@@ -238,13 +248,13 @@ static inline u32 dispc_read_reg(const u16 idx)
|
|
|
|
|
|
static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
|
|
static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
|
|
{
|
|
{
|
|
- const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld];
|
|
|
|
|
|
+ const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
|
|
return REG_GET(rfld.reg, rfld.high, rfld.low);
|
|
return REG_GET(rfld.reg, rfld.high, rfld.low);
|
|
}
|
|
}
|
|
|
|
|
|
static void mgr_fld_write(enum omap_channel channel,
|
|
static void mgr_fld_write(enum omap_channel channel,
|
|
enum mgr_reg_fields regfld, int val) {
|
|
enum mgr_reg_fields regfld, int val) {
|
|
- const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld];
|
|
|
|
|
|
+ const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
|
|
REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
|
|
REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3669,16 +3679,44 @@ static int __init dispc_init_features(struct platform_device *pdev)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static irqreturn_t dispc_irq_handler(int irq, void *arg)
|
|
|
|
+{
|
|
|
|
+ if (!dispc.is_enabled)
|
|
|
|
+ return IRQ_NONE;
|
|
|
|
+
|
|
|
|
+ return dispc.user_handler(irq, dispc.user_data);
|
|
|
|
+}
|
|
|
|
+
|
|
int dispc_request_irq(irq_handler_t handler, void *dev_id)
|
|
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);
|
|
|
|
|
|
+ int r;
|
|
|
|
+
|
|
|
|
+ if (dispc.user_handler != NULL)
|
|
|
|
+ return -EBUSY;
|
|
|
|
+
|
|
|
|
+ dispc.user_handler = handler;
|
|
|
|
+ dispc.user_data = dev_id;
|
|
|
|
+
|
|
|
|
+ /* ensure the dispc_irq_handler sees the values above */
|
|
|
|
+ smp_wmb();
|
|
|
|
+
|
|
|
|
+ r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler,
|
|
|
|
+ IRQF_SHARED, "OMAP DISPC", &dispc);
|
|
|
|
+ if (r) {
|
|
|
|
+ dispc.user_handler = NULL;
|
|
|
|
+ dispc.user_data = NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return r;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(dispc_request_irq);
|
|
EXPORT_SYMBOL(dispc_request_irq);
|
|
|
|
|
|
void dispc_free_irq(void *dev_id)
|
|
void dispc_free_irq(void *dev_id)
|
|
{
|
|
{
|
|
- devm_free_irq(&dispc.pdev->dev, dispc.irq, dev_id);
|
|
|
|
|
|
+ devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc);
|
|
|
|
+
|
|
|
|
+ dispc.user_handler = NULL;
|
|
|
|
+ dispc.user_data = NULL;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(dispc_free_irq);
|
|
EXPORT_SYMBOL(dispc_free_irq);
|
|
|
|
|
|
@@ -3750,6 +3788,12 @@ static int __exit omap_dispchw_remove(struct platform_device *pdev)
|
|
|
|
|
|
static int dispc_runtime_suspend(struct device *dev)
|
|
static int dispc_runtime_suspend(struct device *dev)
|
|
{
|
|
{
|
|
|
|
+ dispc.is_enabled = false;
|
|
|
|
+ /* ensure the dispc_irq_handler sees the is_enabled value */
|
|
|
|
+ smp_wmb();
|
|
|
|
+ /* wait for current handler to finish before turning the DISPC off */
|
|
|
|
+ synchronize_irq(dispc.irq);
|
|
|
|
+
|
|
dispc_save_context();
|
|
dispc_save_context();
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -3763,12 +3807,15 @@ static int dispc_runtime_resume(struct device *dev)
|
|
* _omap_dispc_initial_config(). We can thus use it to detect if
|
|
* _omap_dispc_initial_config(). We can thus use it to detect if
|
|
* we have lost register context.
|
|
* we have lost register context.
|
|
*/
|
|
*/
|
|
- if (REG_GET(DISPC_CONFIG, 2, 1) == OMAP_DSS_LOAD_FRAME_ONLY)
|
|
|
|
- return 0;
|
|
|
|
|
|
+ if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
|
|
|
|
+ _omap_dispc_initial_config();
|
|
|
|
|
|
- _omap_dispc_initial_config();
|
|
|
|
|
|
+ dispc_restore_context();
|
|
|
|
+ }
|
|
|
|
|
|
- dispc_restore_context();
|
|
|
|
|
|
+ dispc.is_enabled = true;
|
|
|
|
+ /* ensure the dispc_irq_handler sees the is_enabled value */
|
|
|
|
+ smp_wmb();
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|