aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sh_mobile_lcdcfb.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-11-29 08:37:35 -0500
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-03-12 17:40:57 -0400
commita67f379d3648746be0dab7b616f2fb838ec0fdfb (patch)
treefd68aa9465adf4de51aa45bda30b5d2bd48aaf8c /drivers/video/sh_mobile_lcdcfb.c
parentfc9e78e6b3d2ba2e96426527b8231f6b7c7b7b96 (diff)
fbdev: sh_mobile_lcdc: Split fb init/cleanup from channel init/cleanup
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c285
1 files changed, 157 insertions, 128 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 6d8c30bf425a..1f8dd83b5fe1 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1427,6 +1427,141 @@ static struct fb_ops sh_mobile_lcdc_ops = {
1427 .fb_set_par = sh_mobile_set_par, 1427 .fb_set_par = sh_mobile_set_par,
1428}; 1428};
1429 1429
1430static void
1431sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
1432{
1433 if (ch->info && ch->info->dev)
1434 unregister_framebuffer(ch->info);
1435}
1436
1437static int __devinit
1438sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
1439{
1440 struct fb_info *info = ch->info;
1441 int ret;
1442
1443 if (info->fbdefio) {
1444 ch->sglist = vmalloc(sizeof(struct scatterlist) *
1445 ch->fb_size >> PAGE_SHIFT);
1446 if (!ch->sglist) {
1447 dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
1448 return -ENOMEM;
1449 }
1450 }
1451
1452 info->bl_dev = ch->bl;
1453
1454 ret = register_framebuffer(info);
1455 if (ret < 0)
1456 return ret;
1457
1458 dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n",
1459 dev_name(ch->lcdc->dev), (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
1460 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
1461 info->var.bits_per_pixel);
1462
1463 /* deferred io mode: disable clock to save power */
1464 if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
1465 sh_mobile_lcdc_clk_off(ch->lcdc);
1466
1467 return ret;
1468}
1469
1470static void
1471sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
1472{
1473 struct fb_info *info = ch->info;
1474
1475 if (!info || !info->device)
1476 return;
1477
1478 if (ch->sglist)
1479 vfree(ch->sglist);
1480
1481 fb_dealloc_cmap(&info->cmap);
1482 framebuffer_release(info);
1483}
1484
1485static int __devinit
1486sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
1487 const struct fb_videomode *mode,
1488 unsigned int num_modes)
1489{
1490 struct sh_mobile_lcdc_priv *priv = ch->lcdc;
1491 struct fb_var_screeninfo *var;
1492 struct fb_info *info;
1493 int ret;
1494
1495 /* Allocate and initialize the frame buffer device. Create the modes
1496 * list and allocate the color map.
1497 */
1498 info = framebuffer_alloc(0, priv->dev);
1499 if (info == NULL) {
1500 dev_err(priv->dev, "unable to allocate fb_info\n");
1501 return -ENOMEM;
1502 }
1503
1504 ch->info = info;
1505
1506 info->flags = FBINFO_FLAG_DEFAULT;
1507 info->fbops = &sh_mobile_lcdc_ops;
1508 info->device = priv->dev;
1509 info->screen_base = ch->fb_mem;
1510 info->pseudo_palette = &ch->pseudo_palette;
1511 info->par = ch;
1512
1513 fb_videomode_to_modelist(mode, num_modes, &info->modelist);
1514
1515 ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
1516 if (ret < 0) {
1517 dev_err(priv->dev, "unable to allocate cmap\n");
1518 return ret;
1519 }
1520
1521 /* Initialize fixed screen information. Restrict pan to 2 lines steps
1522 * for NV12 and NV21.
1523 */
1524 info->fix = sh_mobile_lcdc_fix;
1525 info->fix.smem_start = ch->dma_handle;
1526 info->fix.smem_len = ch->fb_size;
1527 if (ch->format->fourcc == V4L2_PIX_FMT_NV12 ||
1528 ch->format->fourcc == V4L2_PIX_FMT_NV21)
1529 info->fix.ypanstep = 2;
1530
1531 /* Initialize variable screen information using the first mode as
1532 * default. The default Y virtual resolution is twice the panel size to
1533 * allow for double-buffering.
1534 */
1535 var = &info->var;
1536 fb_videomode_to_var(var, mode);
1537 var->width = ch->cfg.panel_cfg.width;
1538 var->height = ch->cfg.panel_cfg.height;
1539 var->yres_virtual = var->yres * 2;
1540 var->activate = FB_ACTIVATE_NOW;
1541
1542 /* Use the legacy API by default for RGB formats, and the FOURCC API
1543 * for YUV formats.
1544 */
1545 if (!ch->format->yuv)
1546 var->bits_per_pixel = ch->format->bpp;
1547 else
1548 var->grayscale = ch->format->fourcc;
1549
1550 ret = sh_mobile_check_var(var, info);
1551 if (ret)
1552 return ret;
1553
1554 if (ch->format->yuv) {
1555 info->fix.line_length = var->xres;
1556 info->fix.visual = FB_VISUAL_FOURCC;
1557 } else {
1558 info->fix.line_length = var->xres * ch->format->bpp / 8;
1559 info->fix.visual = FB_VISUAL_TRUECOLOR;
1560 }
1561
1562 return 0;
1563}
1564
1430/* ----------------------------------------------------------------------------- 1565/* -----------------------------------------------------------------------------
1431 * Backlight 1566 * Backlight
1432 */ 1567 */
@@ -1595,37 +1730,28 @@ static const struct fb_videomode default_720p __devinitconst = {
1595static int sh_mobile_lcdc_remove(struct platform_device *pdev) 1730static int sh_mobile_lcdc_remove(struct platform_device *pdev)
1596{ 1731{
1597 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 1732 struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
1598 struct fb_info *info;
1599 int i; 1733 int i;
1600 1734
1601 fb_unregister_client(&priv->notifier); 1735 fb_unregister_client(&priv->notifier);
1602 1736
1603 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 1737 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
1604 if (priv->ch[i].info && priv->ch[i].info->dev) 1738 sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]);
1605 unregister_framebuffer(priv->ch[i].info);
1606 1739
1607 sh_mobile_lcdc_stop(priv); 1740 sh_mobile_lcdc_stop(priv);
1608 1741
1609 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 1742 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
1610 struct sh_mobile_lcdc_chan *ch = &priv->ch[i]; 1743 struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
1611 1744
1612 info = ch->info;
1613 if (!info || !info->device)
1614 continue;
1615
1616 if (ch->tx_dev) { 1745 if (ch->tx_dev) {
1617 ch->tx_dev->lcdc = NULL; 1746 ch->tx_dev->lcdc = NULL;
1618 module_put(ch->cfg.tx_dev->dev.driver->owner); 1747 module_put(ch->cfg.tx_dev->dev.driver->owner);
1619 } 1748 }
1620 1749
1621 if (ch->sglist) 1750 sh_mobile_lcdc_channel_fb_cleanup(ch);
1622 vfree(ch->sglist);
1623 1751
1624 if (info->screen_base) 1752 if (ch->fb_mem)
1625 dma_free_coherent(&pdev->dev, info->fix.smem_len, 1753 dma_free_coherent(&pdev->dev, ch->fb_size,
1626 info->screen_base, ch->dma_handle); 1754 ch->fb_mem, ch->dma_handle);
1627 fb_dealloc_cmap(&info->cmap);
1628 framebuffer_release(info);
1629 } 1755 }
1630 1756
1631 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 1757 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
@@ -1695,13 +1821,9 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
1695 struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; 1821 struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
1696 const struct fb_videomode *max_mode; 1822 const struct fb_videomode *max_mode;
1697 const struct fb_videomode *mode; 1823 const struct fb_videomode *mode;
1698 struct fb_var_screeninfo *var; 1824 unsigned int num_modes;
1699 struct fb_info *info;
1700 unsigned int max_size; 1825 unsigned int max_size;
1701 int num_modes; 1826 unsigned int i;
1702 void *buf;
1703 int ret;
1704 int i;
1705 1827
1706 mutex_init(&ch->open_lock); 1828 mutex_init(&ch->open_lock);
1707 ch->notify = sh_mobile_lcdc_display_notify; 1829 ch->notify = sh_mobile_lcdc_display_notify;
@@ -1715,19 +1837,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
1715 1837
1716 ch->format = format; 1838 ch->format = format;
1717 1839
1718 /* Allocate the frame buffer device. */
1719 ch->info = framebuffer_alloc(0, priv->dev);
1720 if (!ch->info) {
1721 dev_err(priv->dev, "unable to allocate fb_info\n");
1722 return -ENOMEM;
1723 }
1724
1725 info = ch->info;
1726 info->fbops = &sh_mobile_lcdc_ops;
1727 info->par = ch;
1728 info->pseudo_palette = &ch->pseudo_palette;
1729 info->flags = FBINFO_FLAG_DEFAULT;
1730
1731 /* Iterate through the modes to validate them and find the highest 1840 /* Iterate through the modes to validate them and find the highest
1732 * resolution. 1841 * resolution.
1733 */ 1842 */
@@ -1757,7 +1866,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
1757 dev_dbg(priv->dev, "Found largest videomode %ux%u\n", 1866 dev_dbg(priv->dev, "Found largest videomode %ux%u\n",
1758 max_mode->xres, max_mode->yres); 1867 max_mode->xres, max_mode->yres);
1759 1868
1760 /* Create the mode list. */
1761 if (cfg->lcd_modes == NULL) { 1869 if (cfg->lcd_modes == NULL) {
1762 mode = &default_720p; 1870 mode = &default_720p;
1763 num_modes = 1; 1871 num_modes = 1;
@@ -1766,7 +1874,18 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
1766 num_modes = cfg->num_modes; 1874 num_modes = cfg->num_modes;
1767 } 1875 }
1768 1876
1769 fb_videomode_to_modelist(mode, num_modes, &info->modelist); 1877 ch->display.width = cfg->panel_cfg.width;
1878 ch->display.height = cfg->panel_cfg.height;
1879 ch->display.mode = *mode;
1880
1881 /* Allocate frame buffer memory. */
1882 ch->fb_size = max_size * format->bpp / 8 * 2;
1883 ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle,
1884 GFP_KERNEL);
1885 if (ch->fb_mem == NULL) {
1886 dev_err(priv->dev, "unable to allocate buffer\n");
1887 return -ENOMEM;
1888 }
1770 1889
1771 /* Initialize the transmitter device if present. */ 1890 /* Initialize the transmitter device if present. */
1772 if (cfg->tx_dev) { 1891 if (cfg->tx_dev) {
@@ -1781,76 +1900,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
1781 ch->tx_dev->def_mode = *mode; 1900 ch->tx_dev->def_mode = *mode;
1782 } 1901 }
1783 1902
1784 /* Initialize variable screen information using the first mode as 1903 return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
1785 * default. The default Y virtual resolution is twice the panel size to
1786 * allow for double-buffering.
1787 */
1788 var = &info->var;
1789 fb_videomode_to_var(var, mode);
1790 var->width = cfg->panel_cfg.width;
1791 var->height = cfg->panel_cfg.height;
1792 var->yres_virtual = var->yres * 2;
1793 var->activate = FB_ACTIVATE_NOW;
1794
1795 /* Use the legacy API by default for RGB formats, and the FOURCC API
1796 * for YUV formats.
1797 */
1798 if (!format->yuv)
1799 var->bits_per_pixel = format->bpp;
1800 else
1801 var->grayscale = cfg->fourcc;
1802
1803 /* Make sure the memory size check won't fail. smem_len is initialized
1804 * later based on var.
1805 */
1806 info->fix.smem_len = UINT_MAX;
1807 ret = sh_mobile_check_var(var, info);
1808 if (ret)
1809 return ret;
1810
1811 max_size = max_size * var->bits_per_pixel / 8 * 2;
1812
1813 /* Allocate frame buffer memory and color map. */
1814 buf = dma_alloc_coherent(priv->dev, max_size, &ch->dma_handle,
1815 GFP_KERNEL);
1816 if (!buf) {
1817 dev_err(priv->dev, "unable to allocate buffer\n");
1818 return -ENOMEM;
1819 }
1820
1821 ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
1822 if (ret < 0) {
1823 dev_err(priv->dev, "unable to allocate cmap\n");
1824 dma_free_coherent(priv->dev, max_size, buf, ch->dma_handle);
1825 return ret;
1826 }
1827
1828 /* Initialize fixed screen information. Restrict pan to 2 lines steps
1829 * for NV12 and NV21.
1830 */
1831 info->fix = sh_mobile_lcdc_fix;
1832 info->fix.smem_start = ch->dma_handle;
1833 info->fix.smem_len = max_size;
1834 if (cfg->fourcc == V4L2_PIX_FMT_NV12 ||
1835 cfg->fourcc == V4L2_PIX_FMT_NV21)
1836 info->fix.ypanstep = 2;
1837
1838 if (format->yuv) {
1839 info->fix.line_length = var->xres;
1840 info->fix.visual = FB_VISUAL_FOURCC;
1841 } else {
1842 info->fix.line_length = var->xres * var->bits_per_pixel / 8;
1843 info->fix.visual = FB_VISUAL_TRUECOLOR;
1844 }
1845
1846 info->screen_base = buf;
1847 info->device = priv->dev;
1848
1849 ch->display.width = cfg->panel_cfg.width;
1850 ch->display.height = cfg->panel_cfg.height;
1851 ch->display.mode = *mode;
1852
1853 return 0;
1854} 1904}
1855 1905
1856static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) 1906static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
@@ -1966,31 +2016,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1966 2016
1967 for (i = 0; i < num_channels; i++) { 2017 for (i = 0; i < num_channels; i++) {
1968 struct sh_mobile_lcdc_chan *ch = priv->ch + i; 2018 struct sh_mobile_lcdc_chan *ch = priv->ch + i;
1969 struct fb_info *info = ch->info;
1970
1971 if (info->fbdefio) {
1972 ch->sglist = vmalloc(sizeof(struct scatterlist) *
1973 info->fix.smem_len >> PAGE_SHIFT);
1974 if (!ch->sglist) {
1975 dev_err(&pdev->dev, "cannot allocate sglist\n");
1976 goto err1;
1977 }
1978 }
1979 2019
1980 info->bl_dev = ch->bl; 2020 error = sh_mobile_lcdc_channel_fb_register(ch);
1981 2021 if (error)
1982 error = register_framebuffer(info);
1983 if (error < 0)
1984 goto err1; 2022 goto err1;
1985
1986 dev_info(&pdev->dev, "registered %s/%s as %dx%d %dbpp.\n",
1987 pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
1988 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
1989 info->var.bits_per_pixel);
1990
1991 /* deferred io mode: disable clock to save power */
1992 if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
1993 sh_mobile_lcdc_clk_off(priv);
1994 } 2023 }
1995 2024
1996 /* Failure ignored */ 2025 /* Failure ignored */