diff options
| -rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 109 | ||||
| -rw-r--r-- | drivers/video/sh_mobile_lcdcfb.h | 8 |
2 files changed, 61 insertions, 56 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index fc12e37b55ce..6d377b48c138 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
| @@ -273,7 +273,7 @@ static int sh_mobile_lcdc_sginit(struct fb_info *info, | |||
| 273 | struct list_head *pagelist) | 273 | struct list_head *pagelist) |
| 274 | { | 274 | { |
| 275 | struct sh_mobile_lcdc_chan *ch = info->par; | 275 | struct sh_mobile_lcdc_chan *ch = info->par; |
| 276 | unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT; | 276 | unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT; |
| 277 | struct page *page; | 277 | struct page *page; |
| 278 | int nr_pages = 0; | 278 | int nr_pages = 0; |
| 279 | 279 | ||
| @@ -541,17 +541,6 @@ static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) | |||
| 541 | return var->grayscale > 1; | 541 | return var->grayscale > 1; |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var) | ||
| 545 | { | ||
| 546 | const struct sh_mobile_lcdc_format_info *format; | ||
| 547 | |||
| 548 | if (var->grayscale <= 1) | ||
| 549 | return false; | ||
| 550 | |||
| 551 | format = sh_mobile_format_info(var->grayscale); | ||
| 552 | return format ? format->yuv : false; | ||
| 553 | } | ||
| 554 | |||
| 555 | /* ----------------------------------------------------------------------------- | 544 | /* ----------------------------------------------------------------------------- |
| 556 | * Start, stop and IRQ | 545 | * Start, stop and IRQ |
| 557 | */ | 546 | */ |
| @@ -650,7 +639,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
| 650 | h_total = mode->xres + mode->hsync_len + mode->left_margin | 639 | h_total = mode->xres + mode->hsync_len + mode->left_margin |
| 651 | + mode->right_margin; | 640 | + mode->right_margin; |
| 652 | tmp = h_total / 8; /* HTCN */ | 641 | tmp = h_total / 8; /* HTCN */ |
| 653 | tmp |= (min(mode->xres, var->xres) / 8) << 16; /* HDCN */ | 642 | tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */ |
| 654 | lcdc_write_chan(ch, LDHCNR, tmp); | 643 | lcdc_write_chan(ch, LDHCNR, tmp); |
| 655 | 644 | ||
| 656 | hsync_pos = mode->xres + mode->right_margin; | 645 | hsync_pos = mode->xres + mode->right_margin; |
| @@ -661,7 +650,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
| 661 | /* vertical configuration */ | 650 | /* vertical configuration */ |
| 662 | tmp = mode->yres + mode->vsync_len + mode->upper_margin | 651 | tmp = mode->yres + mode->vsync_len + mode->upper_margin |
| 663 | + mode->lower_margin; /* VTLN */ | 652 | + mode->lower_margin; /* VTLN */ |
| 664 | tmp |= min(mode->yres, var->yres) << 16; /* VDLN */ | 653 | tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */ |
| 665 | lcdc_write_chan(ch, LDVLNR, tmp); | 654 | lcdc_write_chan(ch, LDVLNR, tmp); |
| 666 | 655 | ||
| 667 | tmp = mode->yres + mode->lower_margin; /* VSYNP */ | 656 | tmp = mode->yres + mode->lower_margin; /* VSYNP */ |
| @@ -738,7 +727,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 738 | tmp = ch->format->lddfr; | 727 | tmp = ch->format->lddfr; |
| 739 | 728 | ||
| 740 | if (ch->format->yuv) { | 729 | if (ch->format->yuv) { |
| 741 | switch (ch->info->var.colorspace) { | 730 | switch (ch->colorspace) { |
| 742 | case V4L2_COLORSPACE_REC709: | 731 | case V4L2_COLORSPACE_REC709: |
| 743 | tmp |= LDDFR_CF1; | 732 | tmp |= LDDFR_CF1; |
| 744 | break; | 733 | break; |
| @@ -836,11 +825,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 836 | if (!ch->enabled) | 825 | if (!ch->enabled) |
| 837 | continue; | 826 | continue; |
| 838 | 827 | ||
| 839 | ch->base_addr_y = ch->info->fix.smem_start; | 828 | ch->base_addr_y = ch->dma_handle; |
| 840 | ch->base_addr_c = ch->base_addr_y | 829 | ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual; |
| 841 | + ch->info->var.xres | ||
| 842 | * ch->info->var.yres_virtual; | ||
| 843 | ch->pitch = ch->info->fix.line_length; | ||
| 844 | 830 | ||
| 845 | /* Enable MERAM if possible. */ | 831 | /* Enable MERAM if possible. */ |
| 846 | cfg = ch->cfg.meram_cfg; | 832 | cfg = ch->cfg.meram_cfg; |
| @@ -875,7 +861,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
| 875 | } | 861 | } |
| 876 | 862 | ||
| 877 | ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, | 863 | ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, |
| 878 | ch->info->var.yres, pixelformat, | 864 | ch->yres, pixelformat, |
| 879 | ch->base_addr_y, ch->base_addr_c, | 865 | ch->base_addr_y, ch->base_addr_c, |
| 880 | &ch->base_addr_y, &ch->base_addr_c, | 866 | &ch->base_addr_y, &ch->base_addr_c, |
| 881 | &ch->pitch); | 867 | &ch->pitch); |
| @@ -1037,14 +1023,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
| 1037 | unsigned long new_pan_offset; | 1023 | unsigned long new_pan_offset; |
| 1038 | unsigned long base_addr_y, base_addr_c; | 1024 | unsigned long base_addr_y, base_addr_c; |
| 1039 | unsigned long c_offset; | 1025 | unsigned long c_offset; |
| 1040 | bool yuv = sh_mobile_format_is_yuv(&info->var); | ||
| 1041 | 1026 | ||
| 1042 | if (!yuv) | 1027 | if (!ch->format->yuv) |
| 1043 | new_pan_offset = var->yoffset * info->fix.line_length | 1028 | new_pan_offset = var->yoffset * ch->pitch |
| 1044 | + var->xoffset * (info->var.bits_per_pixel / 8); | 1029 | + var->xoffset * (ch->format->bpp / 8); |
| 1045 | else | 1030 | else |
| 1046 | new_pan_offset = var->yoffset * info->fix.line_length | 1031 | new_pan_offset = var->yoffset * ch->pitch + var->xoffset; |
| 1047 | + var->xoffset; | ||
| 1048 | 1032 | ||
| 1049 | if (new_pan_offset == ch->pan_offset) | 1033 | if (new_pan_offset == ch->pan_offset) |
| 1050 | return 0; /* No change, do nothing */ | 1034 | return 0; /* No change, do nothing */ |
| @@ -1053,12 +1037,11 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
| 1053 | 1037 | ||
| 1054 | /* Set the source address for the next refresh */ | 1038 | /* Set the source address for the next refresh */ |
| 1055 | base_addr_y = ch->dma_handle + new_pan_offset; | 1039 | base_addr_y = ch->dma_handle + new_pan_offset; |
| 1056 | if (yuv) { | 1040 | if (ch->format->yuv) { |
| 1057 | /* Set y offset */ | 1041 | /* Set y offset */ |
| 1058 | c_offset = var->yoffset * info->fix.line_length | 1042 | c_offset = var->yoffset * ch->pitch |
| 1059 | * (info->var.bits_per_pixel - 8) / 8; | 1043 | * (ch->format->bpp - 8) / 8; |
| 1060 | base_addr_c = ch->dma_handle | 1044 | base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual |
| 1061 | + info->var.xres * info->var.yres_virtual | ||
| 1062 | + c_offset; | 1045 | + c_offset; |
| 1063 | /* Set x offset */ | 1046 | /* Set x offset */ |
| 1064 | if (ch->format->fourcc == V4L2_PIX_FMT_NV24) | 1047 | if (ch->format->fourcc == V4L2_PIX_FMT_NV24) |
| @@ -1085,7 +1068,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
| 1085 | ch->base_addr_c = base_addr_c; | 1068 | ch->base_addr_c = base_addr_c; |
| 1086 | 1069 | ||
| 1087 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); | 1070 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); |
| 1088 | if (yuv) | 1071 | if (ch->format->yuv) |
| 1089 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | 1072 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); |
| 1090 | 1073 | ||
| 1091 | if (lcdc_chan_is_sublcd(ch)) | 1074 | if (lcdc_chan_is_sublcd(ch)) |
| @@ -1338,24 +1321,28 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in | |||
| 1338 | static int sh_mobile_set_par(struct fb_info *info) | 1321 | static int sh_mobile_set_par(struct fb_info *info) |
| 1339 | { | 1322 | { |
| 1340 | struct sh_mobile_lcdc_chan *ch = info->par; | 1323 | struct sh_mobile_lcdc_chan *ch = info->par; |
| 1341 | u32 line_length = info->fix.line_length; | ||
| 1342 | int ret; | 1324 | int ret; |
| 1343 | 1325 | ||
| 1344 | sh_mobile_lcdc_stop(ch->lcdc); | 1326 | sh_mobile_lcdc_stop(ch->lcdc); |
| 1345 | 1327 | ||
| 1346 | if (sh_mobile_format_is_yuv(&info->var)) | ||
| 1347 | info->fix.line_length = info->var.xres; | ||
| 1348 | else | ||
| 1349 | info->fix.line_length = info->var.xres | ||
| 1350 | * info->var.bits_per_pixel / 8; | ||
| 1351 | |||
| 1352 | ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var)); | 1328 | ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var)); |
| 1329 | ch->colorspace = info->var.colorspace; | ||
| 1330 | |||
| 1331 | ch->xres = info->var.xres; | ||
| 1332 | ch->xres_virtual = info->var.xres_virtual; | ||
| 1333 | ch->yres = info->var.yres; | ||
| 1334 | ch->yres_virtual = info->var.yres_virtual; | ||
| 1335 | |||
| 1336 | if (ch->format->yuv) | ||
| 1337 | ch->pitch = info->var.xres; | ||
| 1338 | else | ||
| 1339 | ch->pitch = info->var.xres * ch->format->bpp / 8; | ||
| 1353 | 1340 | ||
| 1354 | ret = sh_mobile_lcdc_start(ch->lcdc); | 1341 | ret = sh_mobile_lcdc_start(ch->lcdc); |
| 1355 | if (ret < 0) { | 1342 | if (ret < 0) |
| 1356 | dev_err(info->dev, "%s: unable to restart LCDC\n", __func__); | 1343 | dev_err(info->dev, "%s: unable to restart LCDC\n", __func__); |
| 1357 | info->fix.line_length = line_length; | 1344 | |
| 1358 | } | 1345 | info->fix.line_length = ch->pitch; |
| 1359 | 1346 | ||
| 1360 | if (sh_mobile_format_is_fourcc(&info->var)) { | 1347 | if (sh_mobile_format_is_fourcc(&info->var)) { |
| 1361 | info->fix.type = FB_TYPE_FOURCC; | 1348 | info->fix.type = FB_TYPE_FOURCC; |
| @@ -1384,8 +1371,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info) | |||
| 1384 | /* blank the screen? */ | 1371 | /* blank the screen? */ |
| 1385 | if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { | 1372 | if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { |
| 1386 | struct fb_fillrect rect = { | 1373 | struct fb_fillrect rect = { |
| 1387 | .width = info->var.xres, | 1374 | .width = ch->xres, |
| 1388 | .height = info->var.yres, | 1375 | .height = ch->yres, |
| 1389 | }; | 1376 | }; |
| 1390 | sh_mobile_lcdc_fillrect(info, &rect); | 1377 | sh_mobile_lcdc_fillrect(info, &rect); |
| 1391 | } | 1378 | } |
| @@ -1525,6 +1512,13 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, | |||
| 1525 | info->fix = sh_mobile_lcdc_fix; | 1512 | info->fix = sh_mobile_lcdc_fix; |
| 1526 | info->fix.smem_start = ch->dma_handle; | 1513 | info->fix.smem_start = ch->dma_handle; |
| 1527 | info->fix.smem_len = ch->fb_size; | 1514 | info->fix.smem_len = ch->fb_size; |
| 1515 | info->fix.line_length = ch->pitch; | ||
| 1516 | |||
| 1517 | if (ch->format->yuv) | ||
| 1518 | info->fix.visual = FB_VISUAL_FOURCC; | ||
| 1519 | else | ||
| 1520 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
| 1521 | |||
| 1528 | if (ch->format->fourcc == V4L2_PIX_FMT_NV12 || | 1522 | if (ch->format->fourcc == V4L2_PIX_FMT_NV12 || |
| 1529 | ch->format->fourcc == V4L2_PIX_FMT_NV21) | 1523 | ch->format->fourcc == V4L2_PIX_FMT_NV21) |
| 1530 | info->fix.ypanstep = 2; | 1524 | info->fix.ypanstep = 2; |
| @@ -1552,14 +1546,6 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, | |||
| 1552 | if (ret) | 1546 | if (ret) |
| 1553 | return ret; | 1547 | return ret; |
| 1554 | 1548 | ||
| 1555 | if (ch->format->yuv) { | ||
| 1556 | info->fix.line_length = var->xres; | ||
| 1557 | info->fix.visual = FB_VISUAL_FOURCC; | ||
| 1558 | } else { | ||
| 1559 | info->fix.line_length = var->xres * ch->format->bpp / 8; | ||
| 1560 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
| 1561 | } | ||
| 1562 | |||
| 1563 | return 0; | 1549 | return 0; |
| 1564 | } | 1550 | } |
| 1565 | 1551 | ||
| @@ -1836,8 +1822,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
| 1836 | return -EINVAL; | 1822 | return -EINVAL; |
| 1837 | } | 1823 | } |
| 1838 | 1824 | ||
| 1839 | ch->format = format; | ||
| 1840 | |||
| 1841 | /* Iterate through the modes to validate them and find the highest | 1825 | /* Iterate through the modes to validate them and find the highest |
| 1842 | * resolution. | 1826 | * resolution. |
| 1843 | */ | 1827 | */ |
| @@ -1875,6 +1859,21 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
| 1875 | num_modes = cfg->num_modes; | 1859 | num_modes = cfg->num_modes; |
| 1876 | } | 1860 | } |
| 1877 | 1861 | ||
| 1862 | /* Use the first mode as default. */ | ||
| 1863 | ch->format = format; | ||
| 1864 | ch->xres = mode->xres; | ||
| 1865 | ch->xres_virtual = mode->xres; | ||
| 1866 | ch->yres = mode->yres; | ||
| 1867 | ch->yres_virtual = mode->yres * 2; | ||
| 1868 | |||
| 1869 | if (!format->yuv) { | ||
| 1870 | ch->colorspace = V4L2_COLORSPACE_SRGB; | ||
| 1871 | ch->pitch = ch->xres * format->bpp / 8; | ||
| 1872 | } else { | ||
| 1873 | ch->colorspace = V4L2_COLORSPACE_REC709; | ||
| 1874 | ch->pitch = ch->xres; | ||
| 1875 | } | ||
| 1876 | |||
| 1878 | ch->display.width = cfg->panel_cfg.width; | 1877 | ch->display.width = cfg->panel_cfg.width; |
| 1879 | ch->display.height = cfg->panel_cfg.height; | 1878 | ch->display.height = cfg->panel_cfg.height; |
| 1880 | ch->display.mode = *mode; | 1879 | ch->display.mode = *mode; |
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index cc22b9eaaf0a..19a4cd74c89a 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
| @@ -74,9 +74,15 @@ struct sh_mobile_lcdc_chan { | |||
| 74 | struct completion vsync_completion; | 74 | struct completion vsync_completion; |
| 75 | 75 | ||
| 76 | const struct sh_mobile_lcdc_format_info *format; | 76 | const struct sh_mobile_lcdc_format_info *format; |
| 77 | u32 colorspace; | ||
| 78 | unsigned int xres; | ||
| 79 | unsigned int xres_virtual; | ||
| 80 | unsigned int yres; | ||
| 81 | unsigned int yres_virtual; | ||
| 82 | unsigned int pitch; | ||
| 83 | |||
| 77 | unsigned long base_addr_y; | 84 | unsigned long base_addr_y; |
| 78 | unsigned long base_addr_c; | 85 | unsigned long base_addr_c; |
| 79 | unsigned int pitch; | ||
| 80 | 86 | ||
| 81 | int (*notify)(struct sh_mobile_lcdc_chan *ch, | 87 | int (*notify)(struct sh_mobile_lcdc_chan *ch, |
| 82 | enum sh_mobile_lcdc_entity_event event, | 88 | enum sh_mobile_lcdc_entity_event event, |
