aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sh_mobile_lcdcfb.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-08-31 07:00:58 -0400
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2011-09-05 12:37:14 -0400
commit3ce05599907c604a8af9cefe8c5e0702a30d1112 (patch)
treedb2e9870bda13e9e0ea829497a639a43f5e1d801 /drivers/video/sh_mobile_lcdcfb.c
parentb4bee692e5d5a3beb5b59ca7967c0a98e3efcc26 (diff)
fbdev: sh_mobile_lcdc: Split channel initialization from probe function
Move channel initialization to sh_mobile_lcdc_channel_init() and call the function from sh_mobile_lcdc_probe(). This makes the code more readable and prepares it for fix/var initialization rework. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c247
1 files changed, 129 insertions, 118 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 366315bedc0d..d1576e2b2c02 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1485,15 +1485,129 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
1485 return 0; 1485 return 0;
1486} 1486}
1487 1487
1488static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) 1488static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
1489 struct device *dev)
1489{ 1490{
1491 struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
1492 const struct fb_videomode *max_mode;
1493 const struct fb_videomode *mode;
1494 struct fb_var_screeninfo *var;
1490 struct fb_info *info; 1495 struct fb_info *info;
1491 struct sh_mobile_lcdc_priv *priv; 1496 unsigned int max_size;
1497 int num_cfg;
1498 void *buf;
1499 int ret;
1500 int i;
1501
1502 ch->info = framebuffer_alloc(0, dev);
1503 if (!ch->info) {
1504 dev_err(dev, "unable to allocate fb_info\n");
1505 return -ENOMEM;
1506 }
1507
1508 info = ch->info;
1509 var = &info->var;
1510 info->fbops = &sh_mobile_lcdc_ops;
1511 info->par = ch;
1512
1513 mutex_init(&ch->open_lock);
1514
1515 /* Iterate through the modes to validate them and find the highest
1516 * resolution.
1517 */
1518 max_mode = NULL;
1519 max_size = 0;
1520
1521 for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
1522 unsigned int size = mode->yres * mode->xres;
1523
1524 /* NV12 buffers must have even number of lines */
1525 if ((cfg->nonstd) && cfg->bpp == 12 &&
1526 (mode->yres & 0x1)) {
1527 dev_err(dev, "yres must be multiple of 2 for YCbCr420 "
1528 "mode.\n");
1529 return -EINVAL;
1530 }
1531
1532 if (size > max_size) {
1533 max_mode = mode;
1534 max_size = size;
1535 }
1536 }
1537
1538 if (!max_size)
1539 max_size = MAX_XRES * MAX_YRES;
1540 else
1541 dev_dbg(dev, "Found largest videomode %ux%u\n",
1542 max_mode->xres, max_mode->yres);
1543
1544 info->fix = sh_mobile_lcdc_fix;
1545 info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
1546
1547 /* Only pan in 2 line steps for NV12 */
1548 if (cfg->nonstd && cfg->bpp == 12)
1549 info->fix.ypanstep = 2;
1550
1551 if (cfg->lcd_cfg == NULL) {
1552 mode = &default_720p;
1553 num_cfg = 1;
1554 } else {
1555 mode = cfg->lcd_cfg;
1556 num_cfg = cfg->num_cfg;
1557 }
1558
1559 fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
1560
1561 fb_videomode_to_var(var, mode);
1562 var->width = cfg->lcd_size_cfg.width;
1563 var->height = cfg->lcd_size_cfg.height;
1564 /* Default Y virtual resolution is 2x panel size */
1565 var->yres_virtual = var->yres * 2;
1566 var->activate = FB_ACTIVATE_NOW;
1567
1568 ret = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
1569 if (ret)
1570 return ret;
1571
1572 buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle,
1573 GFP_KERNEL);
1574 if (!buf) {
1575 dev_err(dev, "unable to allocate buffer\n");
1576 return -ENOMEM;
1577 }
1578
1579 info->pseudo_palette = &ch->pseudo_palette;
1580 info->flags = FBINFO_FLAG_DEFAULT;
1581
1582 ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
1583 if (ret < 0) {
1584 dev_err(dev, "unable to allocate cmap\n");
1585 dma_free_coherent(dev, info->fix.smem_len,
1586 buf, ch->dma_handle);
1587 return ret;
1588 }
1589
1590 info->fix.smem_start = ch->dma_handle;
1591 if (var->nonstd)
1592 info->fix.line_length = var->xres;
1593 else
1594 info->fix.line_length = var->xres * (cfg->bpp / 8);
1595
1596 info->screen_base = buf;
1597 info->device = dev;
1598 ch->display_var = *var;
1599
1600 return 0;
1601}
1602
1603static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1604{
1492 struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; 1605 struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
1606 struct sh_mobile_lcdc_priv *priv;
1493 struct resource *res; 1607 struct resource *res;
1608 int num_channels;
1494 int error; 1609 int error;
1495 void *buf; 1610 int i;
1496 int i, j;
1497 1611
1498 if (!pdata) { 1612 if (!pdata) {
1499 dev_err(&pdev->dev, "no platform data defined\n"); 1613 dev_err(&pdev->dev, "no platform data defined\n");
@@ -1525,9 +1639,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1525 priv->irq = i; 1639 priv->irq = i;
1526 atomic_set(&priv->hw_usecnt, -1); 1640 atomic_set(&priv->hw_usecnt, -1);
1527 1641
1528 j = 0; 1642 for (i = 0, num_channels = 0; i < ARRAY_SIZE(pdata->ch); i++) {
1529 for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { 1643 struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels;
1530 struct sh_mobile_lcdc_chan *ch = priv->ch + j;
1531 1644
1532 ch->lcdc = priv; 1645 ch->lcdc = priv;
1533 memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); 1646 memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
@@ -1549,24 +1662,24 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1549 case LCDC_CHAN_MAINLCD: 1662 case LCDC_CHAN_MAINLCD:
1550 ch->enabled = LDCNT2R_ME; 1663 ch->enabled = LDCNT2R_ME;
1551 ch->reg_offs = lcdc_offs_mainlcd; 1664 ch->reg_offs = lcdc_offs_mainlcd;
1552 j++; 1665 num_channels++;
1553 break; 1666 break;
1554 case LCDC_CHAN_SUBLCD: 1667 case LCDC_CHAN_SUBLCD:
1555 ch->enabled = LDCNT2R_SE; 1668 ch->enabled = LDCNT2R_SE;
1556 ch->reg_offs = lcdc_offs_sublcd; 1669 ch->reg_offs = lcdc_offs_sublcd;
1557 j++; 1670 num_channels++;
1558 break; 1671 break;
1559 } 1672 }
1560 } 1673 }
1561 1674
1562 if (!j) { 1675 if (!num_channels) {
1563 dev_err(&pdev->dev, "no channels defined\n"); 1676 dev_err(&pdev->dev, "no channels defined\n");
1564 error = -EINVAL; 1677 error = -EINVAL;
1565 goto err1; 1678 goto err1;
1566 } 1679 }
1567 1680
1568 /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */ 1681 /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
1569 if (j == 2) 1682 if (num_channels == 2)
1570 priv->forced_bpp = pdata->ch[0].bpp; 1683 priv->forced_bpp = pdata->ch[0].bpp;
1571 1684
1572 priv->base = ioremap_nocache(res->start, resource_size(res)); 1685 priv->base = ioremap_nocache(res->start, resource_size(res));
@@ -1581,125 +1694,23 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1581 1694
1582 priv->meram_dev = pdata->meram_dev; 1695 priv->meram_dev = pdata->meram_dev;
1583 1696
1584 for (i = 0; i < j; i++) { 1697 for (i = 0; i < num_channels; i++) {
1585 struct fb_var_screeninfo *var;
1586 const struct fb_videomode *lcd_cfg, *max_cfg = NULL;
1587 struct sh_mobile_lcdc_chan *ch = priv->ch + i; 1698 struct sh_mobile_lcdc_chan *ch = priv->ch + i;
1588 struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
1589 const struct fb_videomode *mode = cfg->lcd_cfg;
1590 unsigned long max_size = 0;
1591 int k;
1592 int num_cfg;
1593
1594 ch->info = framebuffer_alloc(0, &pdev->dev);
1595 if (!ch->info) {
1596 dev_err(&pdev->dev, "unable to allocate fb_info\n");
1597 error = -ENOMEM;
1598 break;
1599 }
1600
1601 info = ch->info;
1602 var = &info->var;
1603 info->fbops = &sh_mobile_lcdc_ops;
1604 info->par = ch;
1605
1606 mutex_init(&ch->open_lock);
1607
1608 for (k = 0, lcd_cfg = mode;
1609 k < cfg->num_cfg && lcd_cfg;
1610 k++, lcd_cfg++) {
1611 unsigned long size = lcd_cfg->yres * lcd_cfg->xres;
1612 /* NV12 buffers must have even number of lines */
1613 if ((cfg->nonstd) && cfg->bpp == 12 &&
1614 (lcd_cfg->yres & 0x1)) {
1615 dev_err(&pdev->dev, "yres must be multiple of 2"
1616 " for YCbCr420 mode.\n");
1617 error = -EINVAL;
1618 goto err1;
1619 }
1620
1621 if (size > max_size) {
1622 max_cfg = lcd_cfg;
1623 max_size = size;
1624 }
1625 }
1626
1627 if (!mode)
1628 max_size = MAX_XRES * MAX_YRES;
1629 else if (max_cfg)
1630 dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n",
1631 max_cfg->xres, max_cfg->yres);
1632
1633 info->fix = sh_mobile_lcdc_fix;
1634 info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
1635
1636 /* Only pan in 2 line steps for NV12 */
1637 if (cfg->nonstd && cfg->bpp == 12)
1638 info->fix.ypanstep = 2;
1639
1640 if (!mode) {
1641 mode = &default_720p;
1642 num_cfg = 1;
1643 } else {
1644 num_cfg = cfg->num_cfg;
1645 }
1646
1647 fb_videomode_to_modelist(mode, num_cfg, &info->modelist);
1648 1699
1649 fb_videomode_to_var(var, mode); 1700 error = sh_mobile_lcdc_channel_init(ch, &pdev->dev);
1650 var->width = cfg->lcd_size_cfg.width;
1651 var->height = cfg->lcd_size_cfg.height;
1652 /* Default Y virtual resolution is 2x panel size */
1653 var->yres_virtual = var->yres * 2;
1654 var->activate = FB_ACTIVATE_NOW;
1655
1656 error = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
1657 if (error) 1701 if (error)
1658 break; 1702 goto err1;
1659
1660 buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
1661 &ch->dma_handle, GFP_KERNEL);
1662 if (!buf) {
1663 dev_err(&pdev->dev, "unable to allocate buffer\n");
1664 error = -ENOMEM;
1665 break;
1666 }
1667
1668 info->pseudo_palette = &ch->pseudo_palette;
1669 info->flags = FBINFO_FLAG_DEFAULT;
1670
1671 error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
1672 if (error < 0) {
1673 dev_err(&pdev->dev, "unable to allocate cmap\n");
1674 dma_free_coherent(&pdev->dev, info->fix.smem_len,
1675 buf, ch->dma_handle);
1676 break;
1677 }
1678
1679 info->fix.smem_start = ch->dma_handle;
1680 if (var->nonstd)
1681 info->fix.line_length = var->xres;
1682 else
1683 info->fix.line_length = var->xres * (cfg->bpp / 8);
1684
1685 info->screen_base = buf;
1686 info->device = &pdev->dev;
1687 ch->display_var = *var;
1688 } 1703 }
1689 1704
1690 if (error)
1691 goto err1;
1692
1693 error = sh_mobile_lcdc_start(priv); 1705 error = sh_mobile_lcdc_start(priv);
1694 if (error) { 1706 if (error) {
1695 dev_err(&pdev->dev, "unable to start hardware\n"); 1707 dev_err(&pdev->dev, "unable to start hardware\n");
1696 goto err1; 1708 goto err1;
1697 } 1709 }
1698 1710
1699 for (i = 0; i < j; i++) { 1711 for (i = 0; i < num_channels; i++) {
1700 struct sh_mobile_lcdc_chan *ch = priv->ch + i; 1712 struct sh_mobile_lcdc_chan *ch = priv->ch + i;
1701 1713 struct fb_info *info = ch->info;
1702 info = ch->info;
1703 1714
1704 if (info->fbdefio) { 1715 if (info->fbdefio) {
1705 ch->sglist = vmalloc(sizeof(struct scatterlist) * 1716 ch->sglist = vmalloc(sizeof(struct scatterlist) *