aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorAnatolij Gustschin <agust@denx.de>2013-01-19 04:59:10 -0500
committerAnatolij Gustschin <agust@denx.de>2013-01-29 03:29:57 -0500
commitb2639b5f1d01f218dc95537a1c352b3a551c4dd5 (patch)
tree220965a5adad447c7cce418035c12c4cfc97be7c /drivers/video
parent5d3cc311a76073f6e0a27c0752f7e41f69e95ea7 (diff)
drivers/video: fsl-diu-fb: fix bugs in interrupt handling
Since commit f74de500 "drivers/video: fsl-diu-fb: streamline enabling of interrupts" the interrupt handling in the driver is broken. Enabling diu interrupt causes an interrupt storm and results in system lockup. The cookie for the interrupt handler function passed to request_irq() is wrong (it must be a pointer to the diu struct, and not the address of the pointer to the diu struct). As a result the interrupt handler can not read diu registers and acknowledge the interrupt. Fix cookie arguments for request_irq() and free_irq(). Registering the diu interrupt handler in probe() must happen before install_fb() calls since this function registers framebuffer devices and if fbcon tries to take over framebuffer after registering a frame buffer device, it will call fb_open of the diu driver and enable the interrupts. At this time the diu interrupt handler must be registered already. Disabling the interrupts in fsl_diu_release() must happen only if all other AOIs are closed. Otherwise closing an overlay plane will disable the interrupts even if the primary frame buffer plane is opened. Add an appropriate check in the release function. Signed-off-by: Anatolij Gustschin <agust@denx.de> Cc: Timur Tabi <timur@tabi.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fsl-diu-fb.c58
1 files changed, 33 insertions, 25 deletions
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 1ca32c51d7cd..d33e8720cbb9 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1232,6 +1232,16 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
1232 return 0; 1232 return 0;
1233} 1233}
1234 1234
1235static inline void fsl_diu_enable_interrupts(struct fsl_diu_data *data)
1236{
1237 u32 int_mask = INT_UNDRUN; /* enable underrun detection */
1238
1239 if (IS_ENABLED(CONFIG_NOT_COHERENT_CACHE))
1240 int_mask |= INT_VSYNC; /* enable vertical sync */
1241
1242 clrbits32(&data->diu_reg->int_mask, int_mask);
1243}
1244
1235/* turn on fb if count == 1 1245/* turn on fb if count == 1
1236 */ 1246 */
1237static int fsl_diu_open(struct fb_info *info, int user) 1247static int fsl_diu_open(struct fb_info *info, int user)
@@ -1251,19 +1261,7 @@ static int fsl_diu_open(struct fb_info *info, int user)
1251 if (res < 0) 1261 if (res < 0)
1252 mfbi->count--; 1262 mfbi->count--;
1253 else { 1263 else {
1254 struct fsl_diu_data *data = mfbi->parent; 1264 fsl_diu_enable_interrupts(mfbi->parent);
1255
1256#ifdef CONFIG_NOT_COHERENT_CACHE
1257 /*
1258 * Enable underrun detection and vertical sync
1259 * interrupts.
1260 */
1261 clrbits32(&data->diu_reg->int_mask,
1262 INT_UNDRUN | INT_VSYNC);
1263#else
1264 /* Enable underrun detection */
1265 clrbits32(&data->diu_reg->int_mask, INT_UNDRUN);
1266#endif
1267 fsl_diu_enable_panel(info); 1265 fsl_diu_enable_panel(info);
1268 } 1266 }
1269 } 1267 }
@@ -1283,9 +1281,18 @@ static int fsl_diu_release(struct fb_info *info, int user)
1283 mfbi->count--; 1281 mfbi->count--;
1284 if (mfbi->count == 0) { 1282 if (mfbi->count == 0) {
1285 struct fsl_diu_data *data = mfbi->parent; 1283 struct fsl_diu_data *data = mfbi->parent;
1284 bool disable = true;
1285 int i;
1286 1286
1287 /* Disable interrupts */ 1287 /* Disable interrupts only if all AOIs are closed */
1288 out_be32(&data->diu_reg->int_mask, 0xffffffff); 1288 for (i = 0; i < NUM_AOIS; i++) {
1289 struct mfb_info *mi = data->fsl_diu_info[i].par;
1290
1291 if (mi->count)
1292 disable = false;
1293 }
1294 if (disable)
1295 out_be32(&data->diu_reg->int_mask, 0xffffffff);
1289 fsl_diu_disable_panel(info); 1296 fsl_diu_disable_panel(info);
1290 } 1297 }
1291 1298
@@ -1614,14 +1621,6 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
1614 out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr); 1621 out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr);
1615 out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr); 1622 out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr);
1616 1623
1617 for (i = 0; i < NUM_AOIS; i++) {
1618 ret = install_fb(&data->fsl_diu_info[i]);
1619 if (ret) {
1620 dev_err(&pdev->dev, "could not register fb %d\n", i);
1621 goto error;
1622 }
1623 }
1624
1625 /* 1624 /*
1626 * Older versions of U-Boot leave interrupts enabled, so disable 1625 * Older versions of U-Boot leave interrupts enabled, so disable
1627 * all of them and clear the status register. 1626 * all of them and clear the status register.
@@ -1630,12 +1629,21 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
1630 in_be32(&data->diu_reg->int_status); 1629 in_be32(&data->diu_reg->int_status);
1631 1630
1632 ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", 1631 ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb",
1633 &data->diu_reg); 1632 data->diu_reg);
1634 if (ret) { 1633 if (ret) {
1635 dev_err(&pdev->dev, "could not claim irq\n"); 1634 dev_err(&pdev->dev, "could not claim irq\n");
1636 goto error; 1635 goto error;
1637 } 1636 }
1638 1637
1638 for (i = 0; i < NUM_AOIS; i++) {
1639 ret = install_fb(&data->fsl_diu_info[i]);
1640 if (ret) {
1641 dev_err(&pdev->dev, "could not register fb %d\n", i);
1642 free_irq(data->irq, data->diu_reg);
1643 goto error;
1644 }
1645 }
1646
1639 sysfs_attr_init(&data->dev_attr.attr); 1647 sysfs_attr_init(&data->dev_attr.attr);
1640 data->dev_attr.attr.name = "monitor"; 1648 data->dev_attr.attr.name = "monitor";
1641 data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; 1649 data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
@@ -1667,7 +1675,7 @@ static int fsl_diu_remove(struct platform_device *pdev)
1667 data = dev_get_drvdata(&pdev->dev); 1675 data = dev_get_drvdata(&pdev->dev);
1668 disable_lcdc(&data->fsl_diu_info[0]); 1676 disable_lcdc(&data->fsl_diu_info[0]);
1669 1677
1670 free_irq(data->irq, &data->diu_reg); 1678 free_irq(data->irq, data->diu_reg);
1671 1679
1672 for (i = 0; i < NUM_AOIS; i++) 1680 for (i = 0; i < NUM_AOIS; i++)
1673 uninstall_fb(&data->fsl_diu_info[i]); 1681 uninstall_fb(&data->fsl_diu_info[i]);