summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorSandor Yu <R01008@freescale.com>2013-09-04 15:40:44 +0800
committerJason Liu <r64343@freescale.com>2013-10-30 09:55:30 +0800
commit56a25cf0d6f8d0f22c64a3df71c5f1f58c829022 (patch)
tree3c273dc9039647f17b25680beaa89b6036c200f4 /drivers/video
parent27aa2c474f580dd2a3a216738eeed911a57f9af1 (diff)
ENGR00277843-01 mxsfb: Allocate frame buffer from DMA pool
- Original frame buffer size is fixed in SZ_2M when driver probing, that can not support more resolution, such as 720p and 1080p. Add function mxsfb_map_videomem/mxsfb_unmap_videomem to replace fixed frame buffer size. Frame buffer size can change with resolution change and application requirement. - Add fb_mmap function implement. - Remove member variable sync from struct mxsfb_info, align the sync definition with mxc_cea_mode[] in mxc_edid.c. - Set recovery from underflow bit. - Fix xres_virtual yres_virtual check issue in function mxsfb_check_var(). Signed-off-by: Sandor Yu <R01008@freescale.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/mxsfb.c177
1 files changed, 133 insertions, 44 deletions
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 5e94efeaa1d2..88b6cc9aa2c8 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -96,9 +96,10 @@
#define CTRL_DF24 (1 << 1)
#define CTRL_RUN (1 << 0)
-#define CTRL1_FIFO_CLEAR (1 << 21)
-#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
-#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
+#define CTRL1_RECOVERY_ON_UNDERFLOW (1 << 24)
+#define CTRL1_FIFO_CLEAR (1 << 21)
+#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
+#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
@@ -149,8 +150,8 @@
#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
-#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negtive edge sampling */
+#define FB_SYNC_OE_LOW_ACT 0x80000000
+#define FB_SYNC_CLK_LAT_FALL 0x40000000
enum mxsfb_devtype {
MXSFB_V3,
@@ -180,7 +181,6 @@ struct mxsfb_info {
unsigned ld_intf_width;
unsigned dotclk_delay;
const struct mxsfb_devdata *devdata;
- u32 sync;
struct regulator *reg_lcd;
};
@@ -210,6 +210,9 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
#define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info))
+static int mxsfb_map_videomem(struct fb_info *info);
+static int mxsfb_unmap_videomem(struct fb_info *info);
+
/* enable lcdif axi clock */
static inline void clk_enable_axi(struct mxsfb_info *host)
{
@@ -315,9 +318,10 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
if (var->yres < MIN_YRES)
var->yres = MIN_YRES;
- var->xres_virtual = var->xres;
-
- var->yres_virtual = var->yres;
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
switch (var->bits_per_pixel) {
case 16:
@@ -389,6 +393,9 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET);
+ /* Recovery on underflow */
+ writel(CTRL1_RECOVERY_ON_UNDERFLOW, host->base + LCDC_CTRL1 + REG_SET);
+
host->enabled = 1;
}
@@ -440,14 +447,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
clk_enable_axi(host);
- line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
- fb_size = fb_info->var.yres_virtual * line_size;
-
- if (fb_size > fb_info->fix.smem_len)
- return -ENOMEM;
-
- fb_info->fix.line_length = line_size;
-
/*
* It seems, you can't re-program the controller if it is still running.
* This may lead into shifted pictures (FIFO issue?).
@@ -461,6 +460,19 @@ static int mxsfb_set_par(struct fb_info *fb_info)
/* clear the FIFOs */
writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET);
+ line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
+ fb_info->fix.line_length = line_size;
+ fb_size = fb_info->var.yres_virtual * line_size;
+
+ /* Reallocate memory */
+ 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;
+ }
+
ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER |
CTRL_SET_BUS_WIDTH(host->ld_intf_width);
@@ -512,9 +524,9 @@ static int mxsfb_set_par(struct fb_info *fb_info)
vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT)
vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
- if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT)
+ if (!(fb_info->var.sync & FB_SYNC_OE_LOW_ACT))
vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
- if (host->sync & MXSFB_SYNC_DOTCLK_FALLING_ACT)
+ if (fb_info->var.sync & FB_SYNC_CLK_LAT_FALL)
vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
writel(vdctrl0, host->base + LCDC_VDCTRL0);
@@ -635,6 +647,34 @@ static int mxsfb_pan_display(struct fb_var_screeninfo *var,
return 0;
}
+static int mxsfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ u32 len;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (offset < info->fix.smem_len) {
+ /* mapping framebuffer memory */
+ len = info->fix.smem_len - offset;
+ vma->vm_pgoff = (info->fix.smem_start + offset) >> PAGE_SHIFT;
+ } else
+ return -EINVAL;
+
+ len = PAGE_ALIGN(len);
+ if (vma->vm_end - vma->vm_start > len)
+ return -EINVAL;
+
+ /* make buffers bufferable */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ dev_dbg(info->device, "mmap remap_pfn_range failed\n");
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
static struct fb_ops mxsfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = mxsfb_check_var,
@@ -642,6 +682,7 @@ static struct fb_ops mxsfb_ops = {
.fb_setcolreg = mxsfb_setcolreg,
.fb_blank = mxsfb_blank,
.fb_pan_display = mxsfb_pan_display,
+ .fb_mmap = mxsfb_mmap,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
@@ -817,10 +858,10 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
if (ret < 0)
goto put_timings_node;
- if (vm.flags & DISPLAY_FLAGS_DE_HIGH)
- host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
+ if (!(vm.flags & DISPLAY_FLAGS_DE_HIGH))
+ fb_vm.sync |= FB_SYNC_OE_LOW_ACT;
if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
- host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT;
+ fb_vm.sync |= FB_SYNC_CLK_LAT_FALL;
fb_add_videomode(&fb_vm, &fb_info->modelist);
}
@@ -835,9 +876,7 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host)
{
struct fb_info *fb_info = &host->fb_info;
struct fb_var_screeninfo *var = &fb_info->var;
- dma_addr_t fb_phys;
- void *fb_virt;
- unsigned fb_size;
+ struct fb_modelist *modelist;
int ret;
fb_info->fbops = &mxsfb_ops;
@@ -852,25 +891,28 @@ static int mxsfb_init_fbinfo(struct mxsfb_info *host)
if (ret)
return ret;
+ /* first video mode in the modelist as default video mode */
+ modelist = list_first_entry(&fb_info->modelist,
+ struct fb_modelist, list);
+ fb_videomode_to_var(var, &modelist->mode);
+
var->nonstd = 0;
var->activate = FB_ACTIVATE_NOW;
var->accel_flags = 0;
var->vmode = FB_VMODE_NONINTERLACED;
- /* Memory allocation for framebuffer */
- fb_size = SZ_2M;
- fb_virt = alloc_pages_exact(fb_size, GFP_DMA);
- if (!fb_virt)
- return -ENOMEM;
+ /* init the color fields */
+ mxsfb_check_var(var, fb_info);
- fb_phys = virt_to_phys(fb_virt);
+ fb_info->fix.line_length =
+ fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
- fb_info->fix.smem_start = fb_phys;
- fb_info->screen_base = fb_virt;
- fb_info->screen_size = fb_info->fix.smem_len = fb_size;
+ /* Memory allocation for framebuffer */
+ if (mxsfb_map_videomem(fb_info) < 0)
+ return -ENOMEM;
if (mxsfb_restore_mode(host))
- memset(fb_virt, 0, fb_size);
+ memset((char *)fb_info->screen_base, 0, fb_info->fix.smem_len);
return 0;
}
@@ -879,7 +921,62 @@ static void mxsfb_free_videomem(struct mxsfb_info *host)
{
struct fb_info *fb_info = &host->fb_info;
- free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len);
+ mxsfb_unmap_videomem(fb_info);
+}
+
+/*!
+ * Allocates the DRAM memory for the frame buffer. This buffer is remapped
+ * into a non-cached, non-buffered, memory region to allow palette and pixel
+ * writes to occur without flushing the cache. Once this area is remapped,
+ * all virtual memory access to the video memory should occur at the new region.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mxsfb_map_videomem(struct fb_info *fbi)
+{
+ if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length)
+ fbi->fix.smem_len = fbi->var.yres_virtual *
+ fbi->fix.line_length;
+
+ fbi->screen_base = dma_alloc_writecombine(fbi->device,
+ fbi->fix.smem_len,
+ (dma_addr_t *)&fbi->fix.smem_start,
+ GFP_DMA | GFP_KERNEL);
+ if (fbi->screen_base == 0) {
+ dev_err(fbi->device, "Unable to allocate framebuffer memory\n");
+ fbi->fix.smem_len = 0;
+ fbi->fix.smem_start = 0;
+ return -EBUSY;
+ }
+
+ dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
+ (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
+
+ fbi->screen_size = fbi->fix.smem_len;
+
+ /* Clear the screen */
+ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+ return 0;
+}
+
+/*!
+ * De-allocates the DRAM memory for the frame buffer.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mxsfb_unmap_videomem(struct fb_info *fbi)
+{
+ dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+ fbi->screen_base, fbi->fix.smem_start);
+ fbi->screen_base = 0;
+ fbi->fix.smem_start = 0;
+ fbi->fix.smem_len = 0;
+ return 0;
}
static struct platform_device_id mxsfb_devtype[] = {
@@ -909,7 +1006,6 @@ static int mxsfb_probe(struct platform_device *pdev)
struct resource *res;
struct mxsfb_info *host;
struct fb_info *fb_info;
- struct fb_modelist *modelist;
struct pinctrl *pinctrl;
int ret;
@@ -977,13 +1073,6 @@ static int mxsfb_probe(struct platform_device *pdev)
if (ret != 0)
goto fb_release;
- modelist = list_first_entry(&fb_info->modelist,
- struct fb_modelist, list);
- fb_videomode_to_var(&fb_info->var, &modelist->mode);
-
- /* init the color fields */
- mxsfb_check_var(&fb_info->var, fb_info);
-
platform_set_drvdata(pdev, fb_info);
ret = register_framebuffer(fb_info);