diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2011-08-31 07:00:58 -0400 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-09-05 12:37:14 -0400 |
commit | 3ce05599907c604a8af9cefe8c5e0702a30d1112 (patch) | |
tree | db2e9870bda13e9e0ea829497a639a43f5e1d801 /drivers/video/sh_mobile_lcdcfb.c | |
parent | b4bee692e5d5a3beb5b59ca7967c0a98e3efcc26 (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.c | 247 |
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 | ||
1488 | static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | 1488 | static 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 | |||
1603 | static 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) * |