aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c110
-rw-r--r--drivers/video/sh_mobile_lcdcfb.h3
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