davinci: fb: Frame Buffer driver for TI DA8xx/OMAP-L1xx
[safe/jmp/linux-2.6] / drivers / video / sm501fb.c
index f94ae84..924d794 100644 (file)
@@ -145,7 +145,7 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
 #define SM501_MEMF_ACCEL               (8)
 
 static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
-                          unsigned int why, size_t size)
+                          unsigned int why, size_t size, u32 smem_len)
 {
        struct sm501fb_par *par;
        struct fb_info *fbi;
@@ -159,6 +159,9 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
                break;
 
        case SM501_MEMF_PANEL:
+               if (size > inf->fbmem_len)
+                       return -ENOMEM;
+
                ptr = inf->fbmem_len - size;
                fbi = inf->fb[HEAD_CRT];
 
@@ -169,10 +172,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
                if (ptr > 0)
                        ptr &= ~(PAGE_SIZE - 1);
 
-               if (fbi && ptr < fbi->fix.smem_len)
-                       return -ENOMEM;
-
-               if (ptr < 0)
+               if (fbi && ptr < smem_len)
                        return -ENOMEM;
 
                break;
@@ -197,7 +197,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
 
        case SM501_MEMF_ACCEL:
                fbi = inf->fb[HEAD_CRT];
-               ptr = fbi ? fbi->fix.smem_len : 0;
+               ptr = fbi ? smem_len : 0;
 
                fbi = inf->fb[HEAD_PANEL];
                if (fbi) {
@@ -413,6 +413,7 @@ static int sm501fb_set_par_common(struct fb_info *info,
        unsigned int mem_type;
        unsigned int clock_type;
        unsigned int head_addr;
+       unsigned int smem_len;
 
        dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
                __func__, var->xres, var->yres, var->bits_per_pixel,
@@ -453,18 +454,20 @@ static int sm501fb_set_par_common(struct fb_info *info,
 
        /* allocate fb memory within 501 */
        info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
-       info->fix.smem_len    = info->fix.line_length * var->yres_virtual;
+       smem_len = info->fix.line_length * var->yres_virtual;
 
        dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
                info->fix.line_length);
 
-       if (sm501_alloc_mem(fbi, &par->screen, mem_type,
-                           info->fix.smem_len)) {
+       if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) {
                dev_err(fbi->dev, "no memory available\n");
                return -ENOMEM;
        }
 
+       mutex_lock(&info->mm_lock);
        info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
+       info->fix.smem_len   = smem_len;
+       mutex_unlock(&info->mm_lock);
 
        info->screen_base = fbi->fbmem + par->screen.sm_addr;
        info->screen_size = info->fix.smem_len;
@@ -637,7 +640,8 @@ static int sm501fb_set_par_crt(struct fb_info *info)
        if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
                /* the head is displaying panel data... */
 
-               sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
+               sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0,
+                               info->fix.smem_len);
                goto out_update;
        }
 
@@ -1289,7 +1293,8 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
 
        par->cursor_regs = info->regs + reg_base;
 
-       ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
+       ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024,
+                             fbi->fix.smem_len);
        if (ret < 0)
                return ret;
 
@@ -1525,16 +1530,16 @@ static int sm501fb_init_fb(struct fb_info *fb,
        }
 
        /* initialise and set the palette */
-       fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);
+       if (fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0)) {
+               dev_err(info->dev, "failed to allocate cmap memory\n");
+               return -ENOMEM;
+       }
        fb_set_cmap(&fb->cmap, fb);
 
        ret = (fb->fbops->fb_check_var)(&fb->var, fb);
        if (ret)
                dev_err(info->dev, "check_var() failed on initial setup?\n");
 
-       /* ensure we've activated our new configuration */
-       (fb->fbops->fb_set_par)(fb);
-
        return 0;
 }
 
@@ -1616,6 +1621,8 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
        if (!fbi)
                return 0;
 
+       mutex_init(&info->fb[head]->mm_lock);
+
        ret = sm501fb_init_fb(info->fb[head], head, drvname);
        if (ret) {
                dev_err(info->dev, "cannot initialise fb %s\n", drvname);