diff options
| -rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 110 | ||||
| -rw-r--r-- | drivers/video/sh_mobile_lcdcfb.h | 3 |
2 files changed, 54 insertions, 59 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index a5027099fb4c..8cb653b107cc 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
| @@ -161,7 +161,7 @@ enum sh_mobile_lcdc_overlay_mode { | |||
| 161 | * @dma_handle: Frame buffer DMA address | 161 | * @dma_handle: Frame buffer DMA address |
| 162 | * @base_addr_y: Overlay base address (RGB or luma component) | 162 | * @base_addr_y: Overlay base address (RGB or luma component) |
| 163 | * @base_addr_c: Overlay base address (chroma component) | 163 | * @base_addr_c: Overlay base address (chroma component) |
| 164 | * @pan_offset: Current pan offset in bytes | 164 | * @pan_y_offset: Panning linear offset in bytes (luma component) |
| 165 | * @format: Current pixelf format | 165 | * @format: Current pixelf format |
| 166 | * @xres: Horizontal visible resolution | 166 | * @xres: Horizontal visible resolution |
| 167 | * @xres_virtual: Horizontal total resolution | 167 | * @xres_virtual: Horizontal total resolution |
| @@ -191,7 +191,7 @@ struct sh_mobile_lcdc_overlay { | |||
| 191 | dma_addr_t dma_handle; | 191 | dma_addr_t dma_handle; |
| 192 | unsigned long base_addr_y; | 192 | unsigned long base_addr_y; |
| 193 | unsigned long base_addr_c; | 193 | unsigned long base_addr_c; |
| 194 | unsigned long pan_offset; | 194 | unsigned long pan_y_offset; |
| 195 | 195 | ||
| 196 | const struct sh_mobile_lcdc_format_info *format; | 196 | const struct sh_mobile_lcdc_format_info *format; |
| 197 | unsigned int xres; | 197 | unsigned int xres; |
| @@ -873,8 +873,8 @@ static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl) | |||
| 873 | } | 873 | } |
| 874 | 874 | ||
| 875 | ovl->base_addr_y = ovl->dma_handle; | 875 | ovl->base_addr_y = ovl->dma_handle; |
| 876 | ovl->base_addr_c = ovl->base_addr_y + ovl->xres | 876 | ovl->base_addr_c = ovl->dma_handle |
| 877 | * ovl->yres_virtual; | 877 | + ovl->xres_virtual * ovl->yres_virtual; |
| 878 | 878 | ||
| 879 | switch (ovl->mode) { | 879 | switch (ovl->mode) { |
| 880 | case LCDC_OVERLAY_BLEND: | 880 | case LCDC_OVERLAY_BLEND: |
| @@ -1111,7 +1111,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 1111 | continue; | 1111 | continue; |
| 1112 | 1112 | ||
| 1113 | ch->base_addr_y = ch->dma_handle; | 1113 | ch->base_addr_y = ch->dma_handle; |
| 1114 | ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual; | 1114 | ch->base_addr_c = ch->dma_handle |
| 1115 | + ch->xres_virtual * ch->yres_virtual; | ||
| 1115 | ch->line_size = ch->pitch; | 1116 | ch->line_size = ch->pitch; |
| 1116 | 1117 | ||
| 1117 | /* Enable MERAM if possible. */ | 1118 | /* Enable MERAM if possible. */ |
| @@ -1505,39 +1506,36 @@ static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var, | |||
| 1505 | struct sh_mobile_lcdc_overlay *ovl = info->par; | 1506 | struct sh_mobile_lcdc_overlay *ovl = info->par; |
| 1506 | unsigned long base_addr_y; | 1507 | unsigned long base_addr_y; |
| 1507 | unsigned long base_addr_c; | 1508 | unsigned long base_addr_c; |
| 1508 | unsigned long pan_offset; | 1509 | unsigned long y_offset; |
| 1509 | unsigned long c_offset; | 1510 | unsigned long c_offset; |
| 1510 | 1511 | ||
| 1511 | if (!ovl->format->yuv) | 1512 | if (!ovl->format->yuv) { |
| 1512 | pan_offset = var->yoffset * ovl->pitch | 1513 | y_offset = (var->yoffset * ovl->xres_virtual + var->xoffset) |
| 1513 | + var->xoffset * (ovl->format->bpp / 8); | 1514 | * ovl->format->bpp / 8; |
| 1514 | else | 1515 | c_offset = 0; |
| 1515 | pan_offset = var->yoffset * ovl->pitch + var->xoffset; | 1516 | } else { |
| 1517 | unsigned int xsub = ovl->format->bpp < 24 ? 2 : 1; | ||
| 1518 | unsigned int ysub = ovl->format->bpp < 16 ? 2 : 1; | ||
| 1519 | |||
| 1520 | y_offset = var->yoffset * ovl->xres_virtual + var->xoffset; | ||
| 1521 | c_offset = var->yoffset / ysub * ovl->xres_virtual * 2 / xsub | ||
| 1522 | + var->xoffset * 2 / xsub; | ||
| 1523 | } | ||
| 1516 | 1524 | ||
| 1517 | if (pan_offset == ovl->pan_offset) | 1525 | /* If the Y offset hasn't changed, the C offset hasn't either. There's |
| 1518 | return 0; /* No change, do nothing */ | 1526 | * nothing to do in that case. |
| 1527 | */ | ||
| 1528 | if (y_offset == ovl->pan_y_offset) | ||
| 1529 | return 0; | ||
| 1519 | 1530 | ||
| 1520 | /* Set the source address for the next refresh */ | 1531 | /* Set the source address for the next refresh */ |
| 1521 | base_addr_y = ovl->dma_handle + pan_offset; | 1532 | base_addr_y = ovl->dma_handle + y_offset; |
| 1533 | base_addr_c = ovl->dma_handle + ovl->xres_virtual * ovl->yres_virtual | ||
| 1534 | + c_offset; | ||
| 1522 | 1535 | ||
| 1523 | ovl->base_addr_y = base_addr_y; | 1536 | ovl->base_addr_y = base_addr_y; |
| 1524 | ovl->base_addr_c = base_addr_y; | 1537 | ovl->base_addr_c = base_addr_c; |
| 1525 | 1538 | ovl->pan_y_offset = y_offset; | |
| 1526 | if (ovl->format->yuv) { | ||
| 1527 | /* Set Y offset */ | ||
| 1528 | c_offset = var->yoffset * ovl->pitch | ||
| 1529 | * (ovl->format->bpp - 8) / 8; | ||
| 1530 | base_addr_c = ovl->dma_handle | ||
| 1531 | + ovl->xres * ovl->yres_virtual | ||
| 1532 | + c_offset; | ||
| 1533 | /* Set X offset */ | ||
| 1534 | if (ovl->format->fourcc == V4L2_PIX_FMT_NV24) | ||
| 1535 | base_addr_c += 2 * var->xoffset; | ||
| 1536 | else | ||
| 1537 | base_addr_c += var->xoffset; | ||
| 1538 | |||
| 1539 | ovl->base_addr_c = base_addr_c; | ||
| 1540 | } | ||
| 1541 | 1539 | ||
| 1542 | lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index)); | 1540 | lcdc_write(ovl->channel->lcdc, LDBCR, LDBCR_UPC(ovl->index)); |
| 1543 | 1541 | ||
| @@ -1547,8 +1545,6 @@ static int sh_mobile_lcdc_overlay_pan(struct fb_var_screeninfo *var, | |||
| 1547 | lcdc_write(ovl->channel->lcdc, LDBCR, | 1545 | lcdc_write(ovl->channel->lcdc, LDBCR, |
| 1548 | LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index)); | 1546 | LDBCR_UPF(ovl->index) | LDBCR_UPD(ovl->index)); |
| 1549 | 1547 | ||
| 1550 | ovl->pan_offset = pan_offset; | ||
| 1551 | |||
| 1552 | return 0; | 1548 | return 0; |
| 1553 | } | 1549 | } |
| 1554 | 1550 | ||
| @@ -1814,35 +1810,33 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, | |||
| 1814 | struct sh_mobile_lcdc_chan *ch = info->par; | 1810 | struct sh_mobile_lcdc_chan *ch = info->par; |
| 1815 | struct sh_mobile_lcdc_priv *priv = ch->lcdc; | 1811 | struct sh_mobile_lcdc_priv *priv = ch->lcdc; |
| 1816 | unsigned long ldrcntr; | 1812 | unsigned long ldrcntr; |
| 1817 | unsigned long new_pan_offset; | 1813 | unsigned long base_addr_y, base_addr_c; |
| 1818 | unsigned long base_addr_y, base_addr_c = 0; | 1814 | unsigned long y_offset; |
| 1819 | unsigned long c_offset; | 1815 | unsigned long c_offset; |
| 1820 | 1816 | ||
| 1821 | if (!ch->format->yuv) | 1817 | if (!ch->format->yuv) { |
| 1822 | new_pan_offset = var->yoffset * ch->pitch | 1818 | y_offset = (var->yoffset * ch->xres_virtual + var->xoffset) |
| 1823 | + var->xoffset * (ch->format->bpp / 8); | 1819 | * ch->format->bpp / 8; |
| 1824 | else | 1820 | c_offset = 0; |
| 1825 | new_pan_offset = var->yoffset * ch->pitch + var->xoffset; | 1821 | } else { |
| 1822 | unsigned int xsub = ch->format->bpp < 24 ? 2 : 1; | ||
| 1823 | unsigned int ysub = ch->format->bpp < 16 ? 2 : 1; | ||
| 1826 | 1824 | ||
| 1827 | if (new_pan_offset == ch->pan_offset) | 1825 | y_offset = var->yoffset * ch->xres_virtual + var->xoffset; |
| 1828 | return 0; /* No change, do nothing */ | 1826 | c_offset = var->yoffset / ysub * ch->xres_virtual * 2 / xsub |
| 1827 | + var->xoffset * 2 / xsub; | ||
| 1828 | } | ||
| 1829 | 1829 | ||
| 1830 | ldrcntr = lcdc_read(priv, _LDRCNTR); | 1830 | /* If the Y offset hasn't changed, the C offset hasn't either. There's |
| 1831 | * nothing to do in that case. | ||
| 1832 | */ | ||
| 1833 | if (y_offset == ch->pan_y_offset) | ||
| 1834 | return 0; | ||
| 1831 | 1835 | ||
| 1832 | /* Set the source address for the next refresh */ | 1836 | /* Set the source address for the next refresh */ |
| 1833 | base_addr_y = ch->dma_handle + new_pan_offset; | 1837 | base_addr_y = ch->dma_handle + y_offset; |
| 1834 | if (ch->format->yuv) { | 1838 | base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual |
| 1835 | /* Set y offset */ | 1839 | + c_offset; |
| 1836 | c_offset = var->yoffset * ch->pitch | ||
| 1837 | * (ch->format->bpp - 8) / 8; | ||
| 1838 | base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual | ||
| 1839 | + c_offset; | ||
| 1840 | /* Set x offset */ | ||
| 1841 | if (ch->format->fourcc == V4L2_PIX_FMT_NV24) | ||
| 1842 | base_addr_c += 2 * var->xoffset; | ||
| 1843 | else | ||
| 1844 | base_addr_c += var->xoffset; | ||
| 1845 | } | ||
| 1846 | 1840 | ||
| 1847 | if (ch->cache) | 1841 | if (ch->cache) |
| 1848 | sh_mobile_meram_cache_update(priv->meram_dev, ch->cache, | 1842 | sh_mobile_meram_cache_update(priv->meram_dev, ch->cache, |
| @@ -1851,17 +1845,18 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, | |||
| 1851 | |||
