summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobby Cai <robby.cai@nxp.com>2017-04-10 21:02:39 +0800
committerivan.liu <xiaowen.liu@nxp.com>2017-05-24 18:01:47 +0800
commit412c4f67670839ae20ca40908ddb3b99619ad3ad (patch)
treebd5d58d8d6b7974f7d2b12e52bbc84a36b638e56
parent801cca972070470e4b6e8cd4b6d3790e89025bb5 (diff)
downloadimx-v4.1-412c4f67670839ae20ca40908ddb3b99619ad3ad.tar.gz
MLK-14941: mxsfb: add ARGB32 and ABGR32 format support
add a property in dts called 'fbpix' to assign the pixel format for framebuffer. note 'bits-per-pixel' has priority over 'fbpix', so please set them in pair. if 'bits-per-pixel' is set to 16 and no 'fbpix' is set, defaults to RGB565. example for 32bit setting (tested on i.mx7d): display0: display { - bits-per-pixel = <16>; + bits-per-pixel = <32>; bus-width = <24>; + fbpix = "ABGR32"; Signed-off-by: Robby Cai <robby.cai@nxp.com>
-rw-r--r--drivers/video/fbdev/mxsfb.c90
-rw-r--r--include/uapi/linux/videodev2.h1
2 files changed, 85 insertions, 6 deletions
diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c
index 9ab4b6fd1d4f..3cec53435a3c 100644
--- a/drivers/video/fbdev/mxsfb.c
+++ b/drivers/video/fbdev/mxsfb.c
@@ -136,6 +136,8 @@
#define CTRL1_IRQ_STATUS_SHIFT 8
#define CTRL2_OUTSTANDING_REQS__REQ_16 (4 << 21)
+#define CTRL2_ODD_LINE_PATTERN_BGR (5 << 16)
+#define CTRL2_EVEN_LINE_PATTERN_BGR (5 << 12)
#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
@@ -261,6 +263,7 @@ struct mxsfb_info {
int id;
struct fb_var_screeninfo var;
struct pm_qos_request pm_qos_req;
+ u32 pix_fmt;
#ifdef CONFIG_FB_MXC_OVERLAY
struct mxsfb_layer overlay;
@@ -533,6 +536,25 @@ static const struct fb_bitfield def_argb32[] = {
}
};
+static const struct fb_bitfield def_abgr32[] = {
+ [RED] = {
+ .offset = 0,
+ .length = 8,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ },
+ [BLUE] = {
+ .offset = 16,
+ .length = 8,
+ },
+ [TRANSP] = {
+ .offset = 24,
+ .length = 8,
+ }
+};
+
#define bitfield_is_equal(f1, f2) (!memcmp(&(f1), &(f2), sizeof(f1)))
static inline bool pixfmt_is_equal(struct fb_var_screeninfo *var,
@@ -546,6 +568,32 @@ static inline bool pixfmt_is_equal(struct fb_var_screeninfo *var,
return false;
}
+static const struct fb_bitfield* pixfmt_to_bf(u32 pix_fmt)
+{
+ if (pix_fmt == V4L2_PIX_FMT_RGB565)
+ return def_rgb565;
+ else if (pix_fmt == V4L2_PIX_FMT_RGB666)
+ return def_rgb666;
+ else if (pix_fmt == V4L2_PIX_FMT_RGB24)
+ return def_rgb888;
+ else if (pix_fmt == V4L2_PIX_FMT_ARGB32)
+ return def_argb32;
+ else if (pix_fmt == V4L2_PIX_FMT_ABGR32)
+ return def_abgr32;
+ else {
+ pr_err("unsupported pix format\n");
+ return NULL;
+ }
+}
+
+static inline bool need_swizzle_rgb(struct fb_var_screeninfo *var)
+{
+ if (pixfmt_is_equal(var, def_abgr32))
+ return true;
+
+ return false;
+}
+
static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
@@ -637,7 +685,10 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
break;
case STMLCDIF_24BIT:
/* real 24 bit */
- rgb = def_rgb888;
+ if (host->pix_fmt && pixfmt_to_bf(host->pix_fmt))
+ rgb = pixfmt_to_bf(host->pix_fmt);
+ else
+ rgb = def_rgb888;
break;
default:
/*
@@ -722,8 +773,10 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
}
clk_enable_pix(host);
- writel(CTRL2_OUTSTANDING_REQS__REQ_16,
- host->base + LCDC_V4_CTRL2 + REG_SET);
+ reg = CTRL2_OUTSTANDING_REQS__REQ_16;
+ if (need_swizzle_rgb(&(fb_info->var)))
+ reg |= CTRL2_ODD_LINE_PATTERN_BGR | CTRL2_EVEN_LINE_PATTERN_BGR;
+ writel(reg, host->base + LCDC_V4_CTRL2 + REG_SET);
/* if it was disabled, re-enable the mode again */
writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET);
@@ -836,9 +889,12 @@ static int mxsfb_set_par(struct fb_info *fb_info)
fb_info->fix.line_length = line_size;
fb_size = fb_info->var.yres_virtual * line_size;
- if (fb_size > fb_info->fix.smem_len) {
- dev_err(&host->pdev->dev, "exceeds the fb buffer size limit!\n");
- return -ENOMEM;
+ if (!fb_info->fix.smem_start || fb_size > fb_info->fix.smem_len) {
+ if (fb_info->fix.smem_start)
+ mxsfb_unmap_videomem(fb_info);
+
+ if (mxsfb_map_videomem(fb_info) < 0)
+ return -ENOMEM;
}
/*
@@ -1346,6 +1402,7 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
struct device_node *display_np;
struct device_node *timings_np;
struct display_timings *timings = NULL;
+ const char *pixfmt;
const char *disp_dev;
u32 width;
int i;
@@ -1391,6 +1448,27 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
goto put_display_node;
}
+ ret = of_property_read_string(display_np, "fbpix", &pixfmt);
+ if (ret) {
+ host->pix_fmt = 0;
+ dev_warn(dev, "not find property pix fmt\n");
+ } else {
+ if (!strncmp(pixfmt, "RGB565", 6))
+ host->pix_fmt = V4L2_PIX_FMT_RGB565;
+ else if (!strncmp(pixfmt, "RGB666", 6))
+ host->pix_fmt = V4L2_PIX_FMT_RGB666;
+ else if (!strncmp(pixfmt, "RGB888", 6))
+ host->pix_fmt = V4L2_PIX_FMT_RGB24;
+ else if (!strncmp(pixfmt, "ARGB32", 6))
+ host->pix_fmt = V4L2_PIX_FMT_ARGB32;
+ else if (!strncmp(pixfmt, "ABGR32", 6))
+ host->pix_fmt = V4L2_PIX_FMT_ABGR32;
+ else {
+ dev_warn(dev, "no pix fmt assigned, use default\n");
+ host->pix_fmt = 0;
+ }
+ }
+
ret = of_property_read_string(np, "disp-dev", &disp_dev);
if (!ret) {
memcpy(host->disp_dev, disp_dev, strlen(disp_dev));
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 30cba6d34193..37602689c755 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -388,6 +388,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16 XRGB-5-5-5 BE */
#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */
#define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */
+#define V4L2_PIX_FMT_RGB666 v4l2_fourcc('R', 'G', 'B', 'H') /* 18 RGB-6-6-6 */
#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */
#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */