fbdev: sh_mobile_lcdc: Store configuration in channel structure
Store the frame buffer configuration (colorspace, visible/virtual
horizontal and vertical resolutions and line pitch) in the
sh_mobile_lcdc_chan structure, and use it instead of accessing fb_info.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index fc12e37..6d377b4 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -273,7 +273,7 @@
struct list_head *pagelist)
{
struct sh_mobile_lcdc_chan *ch = info->par;
- unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT;
+ unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT;
struct page *page;
int nr_pages = 0;
@@ -541,17 +541,6 @@
return var->grayscale > 1;
}
-static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
-{
- const struct sh_mobile_lcdc_format_info *format;
-
- if (var->grayscale <= 1)
- return false;
-
- format = sh_mobile_format_info(var->grayscale);
- return format ? format->yuv : false;
-}
-
/* -----------------------------------------------------------------------------
* Start, stop and IRQ
*/
@@ -650,7 +639,7 @@
h_total = mode->xres + mode->hsync_len + mode->left_margin
+ mode->right_margin;
tmp = h_total / 8; /* HTCN */
- tmp |= (min(mode->xres, var->xres) / 8) << 16; /* HDCN */
+ tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */
lcdc_write_chan(ch, LDHCNR, tmp);
hsync_pos = mode->xres + mode->right_margin;
@@ -661,7 +650,7 @@
/* vertical configuration */
tmp = mode->yres + mode->vsync_len + mode->upper_margin
+ mode->lower_margin; /* VTLN */
- tmp |= min(mode->yres, var->yres) << 16; /* VDLN */
+ tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */
lcdc_write_chan(ch, LDVLNR, tmp);
tmp = mode->yres + mode->lower_margin; /* VSYNP */
@@ -738,7 +727,7 @@
tmp = ch->format->lddfr;
if (ch->format->yuv) {
- switch (ch->info->var.colorspace) {
+ switch (ch->colorspace) {
case V4L2_COLORSPACE_REC709:
tmp |= LDDFR_CF1;
break;
@@ -836,11 +825,8 @@
if (!ch->enabled)
continue;
- ch->base_addr_y = ch->info->fix.smem_start;
- ch->base_addr_c = ch->base_addr_y
- + ch->info->var.xres
- * ch->info->var.yres_virtual;
- ch->pitch = ch->info->fix.line_length;
+ ch->base_addr_y = ch->dma_handle;
+ ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual;
/* Enable MERAM if possible. */
cfg = ch->cfg.meram_cfg;
@@ -875,7 +861,7 @@
}
ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
- ch->info->var.yres, pixelformat,
+ ch->yres, pixelformat,
ch->base_addr_y, ch->base_addr_c,
&ch->base_addr_y, &ch->base_addr_c,
&ch->pitch);
@@ -1037,14 +1023,12 @@
unsigned long new_pan_offset;
unsigned long base_addr_y, base_addr_c;
unsigned long c_offset;
- bool yuv = sh_mobile_format_is_yuv(&info->var);
- if (!yuv)
- new_pan_offset = var->yoffset * info->fix.line_length
- + var->xoffset * (info->var.bits_per_pixel / 8);
+ if (!ch->format->yuv)
+ new_pan_offset = var->yoffset * ch->pitch
+ + var->xoffset * (ch->format->bpp / 8);
else
- new_pan_offset = var->yoffset * info->fix.line_length
- + var->xoffset;
+ new_pan_offset = var->yoffset * ch->pitch + var->xoffset;
if (new_pan_offset == ch->pan_offset)
return 0; /* No change, do nothing */
@@ -1053,12 +1037,11 @@
/* Set the source address for the next refresh */
base_addr_y = ch->dma_handle + new_pan_offset;
- if (yuv) {
+ if (ch->format->yuv) {
/* Set y offset */
- c_offset = var->yoffset * info->fix.line_length
- * (info->var.bits_per_pixel - 8) / 8;
- base_addr_c = ch->dma_handle
- + info->var.xres * info->var.yres_virtual
+ c_offset = var->yoffset * ch->pitch
+ * (ch->format->bpp - 8) / 8;
+ base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual
+ c_offset;
/* Set x offset */
if (ch->format->fourcc == V4L2_PIX_FMT_NV24)
@@ -1085,7 +1068,7 @@
ch->base_addr_c = base_addr_c;
lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
- if (yuv)
+ if (ch->format->yuv)
lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
if (lcdc_chan_is_sublcd(ch))
@@ -1338,24 +1321,28 @@
static int sh_mobile_set_par(struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
- u32 line_length = info->fix.line_length;
int ret;
sh_mobile_lcdc_stop(ch->lcdc);
- if (sh_mobile_format_is_yuv(&info->var))
- info->fix.line_length = info->var.xres;
- else
- info->fix.line_length = info->var.xres
- * info->var.bits_per_pixel / 8;
-
ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var));
+ ch->colorspace = info->var.colorspace;
+
+ ch->xres = info->var.xres;
+ ch->xres_virtual = info->var.xres_virtual;
+ ch->yres = info->var.yres;
+ ch->yres_virtual = info->var.yres_virtual;
+
+ if (ch->format->yuv)
+ ch->pitch = info->var.xres;
+ else
+ ch->pitch = info->var.xres * ch->format->bpp / 8;
ret = sh_mobile_lcdc_start(ch->lcdc);
- if (ret < 0) {
+ if (ret < 0)
dev_err(info->dev, "%s: unable to restart LCDC\n", __func__);
- info->fix.line_length = line_length;
- }
+
+ info->fix.line_length = ch->pitch;
if (sh_mobile_format_is_fourcc(&info->var)) {
info->fix.type = FB_TYPE_FOURCC;
@@ -1384,8 +1371,8 @@
/* blank the screen? */
if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) {
struct fb_fillrect rect = {
- .width = info->var.xres,
- .height = info->var.yres,
+ .width = ch->xres,
+ .height = ch->yres,
};
sh_mobile_lcdc_fillrect(info, &rect);
}
@@ -1525,6 +1512,13 @@
info->fix = sh_mobile_lcdc_fix;
info->fix.smem_start = ch->dma_handle;
info->fix.smem_len = ch->fb_size;
+ info->fix.line_length = ch->pitch;
+
+ if (ch->format->yuv)
+ info->fix.visual = FB_VISUAL_FOURCC;
+ else
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+
if (ch->format->fourcc == V4L2_PIX_FMT_NV12 ||
ch->format->fourcc == V4L2_PIX_FMT_NV21)
info->fix.ypanstep = 2;
@@ -1552,14 +1546,6 @@
if (ret)
return ret;
- if (ch->format->yuv) {
- info->fix.line_length = var->xres;
- info->fix.visual = FB_VISUAL_FOURCC;
- } else {
- info->fix.line_length = var->xres * ch->format->bpp / 8;
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- }
-
return 0;
}
@@ -1836,8 +1822,6 @@
return -EINVAL;
}
- ch->format = format;
-
/* Iterate through the modes to validate them and find the highest
* resolution.
*/
@@ -1875,6 +1859,21 @@
num_modes = cfg->num_modes;
}
+ /* Use the first mode as default. */
+ ch->format = format;
+ ch->xres = mode->xres;
+ ch->xres_virtual = mode->xres;
+ ch->yres = mode->yres;
+ ch->yres_virtual = mode->yres * 2;
+
+ if (!format->yuv) {
+ ch->colorspace = V4L2_COLORSPACE_SRGB;
+ ch->pitch = ch->xres * format->bpp / 8;
+ } else {
+ ch->colorspace = V4L2_COLORSPACE_REC709;
+ ch->pitch = ch->xres;
+ }
+
ch->display.width = cfg->panel_cfg.width;
ch->display.height = cfg->panel_cfg.height;
ch->display.mode = *mode;
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index cc22b9e..19a4cd7 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -74,9 +74,15 @@
struct completion vsync_completion;
const struct sh_mobile_lcdc_format_info *format;
+ u32 colorspace;
+ unsigned int xres;
+ unsigned int xres_virtual;
+ unsigned int yres;
+ unsigned int yres_virtual;
+ unsigned int pitch;
+
unsigned long base_addr_y;
unsigned long base_addr_c;
- unsigned int pitch;
int (*notify)(struct sh_mobile_lcdc_chan *ch,
enum sh_mobile_lcdc_entity_event event,