Skip to content

Commit

Permalink
[ARM] pxafb: allow video memory size to be configurable
Browse files Browse the repository at this point in the history
The amount of video memory size is decided according to the following
order:

1. <xres> x <yres> x <bits_per_pixel> by default, which is the backward
   compatible way

2. size specified in platform data

3. size specified in module parameter 'options' string or specified in
   kernel boot command line (see updated Documentation/fb/pxafb.txt)

And now since the memory is allocated from system memory, the pxafb_mmap
can be removed and the default fb_mmap() should be working all right.

Also, since we now have introduced the 'struct pxafb_dma_buff' for DMA
descriptors and palettes, the allocation can be separated cleanly.

NOTE: the LCD DMA actually supports chained transfer (i.e. page-based
transfers), to simplify the logic and keep the performance (with less
TLB misses when accessing from memory mapped user space), the memory
is allocated by alloc_pages_*() to ensures it's physical contiguous.

Signed-off-by: Eric Miao <[email protected]>
Signed-off-by: Eric Miao <ycmiao@ycmiao-hp520.(none)>
  • Loading branch information
Eric Miao committed Dec 29, 2008
1 parent 5bfb409 commit 77e1967
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 92 deletions.
8 changes: 6 additions & 2 deletions Documentation/fb/pxafb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ The driver supports the following options, either via
options=<OPTIONS> when modular or video=pxafb:<OPTIONS> when built in.

For example:
modprobe pxafb options=mode:640x480-8,passive
modprobe pxafb options=vmem:2M,mode:640x480-8,passive
or on the kernel command line
video=pxafb:mode:640x480-8,passive
video=pxafb:vmem:2M,mode:640x480-8,passive

vmem: VIDEO_MEM_SIZE
Amount of video memory to allocate (can be suffixed with K or M
for kilobytes or megabytes)

mode:XRESxYRES[-BPP]
XRES == LCCR1_PPL + 1
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-pxa/include/mach/pxafb.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ struct pxafb_mach_info {
unsigned int num_modes;

unsigned int lcd_conn;
unsigned long video_mem_size;

u_int fixed_modes:1,
cmap_inverse:1,
Expand Down
131 changes: 54 additions & 77 deletions drivers/video/pxafb.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
struct pxafb_info *);
static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);

static unsigned long video_mem_size = 0;

static inline unsigned long
lcd_readl(struct pxafb_info *fbi, unsigned int off)
{
Expand Down Expand Up @@ -498,20 +500,6 @@ static int pxafb_blank(int blank, struct fb_info *info)
return 0;
}

static int pxafb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;

if (off < info->fix.smem_len) {
vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
return -EINVAL;
}

static struct fb_ops pxafb_ops = {
.owner = THIS_MODULE,
.fb_check_var = pxafb_check_var,
Expand All @@ -521,7 +509,6 @@ static struct fb_ops pxafb_ops = {
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = pxafb_blank,
.fb_mmap = pxafb_mmap,
};

/*
Expand Down Expand Up @@ -614,7 +601,7 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
dma_desc = &fbi->dma_buff->dma_desc[dma];
dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]);

dma_desc->fsadr = fbi->screen_dma + offset;
dma_desc->fsadr = fbi->video_mem_phys + offset;
dma_desc->fidr = 0;
dma_desc->ldcmd = size;

Expand Down Expand Up @@ -1267,69 +1254,30 @@ static int pxafb_resume(struct platform_device *dev)
#define pxafb_resume NULL
#endif

/*
* pxafb_map_video_memory():
* 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.
*/
static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
static int __devinit pxafb_init_video_memory(struct pxafb_info *fbi)
{
/*
* We reserve one page for the palette, plus the size
* of the framebuffer.
*/
fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
&fbi->map_dma, GFP_KERNEL);

if (fbi->map_cpu) {
/* prevent initial garbage on screen */
memset(fbi->map_cpu, 0, fbi->map_size);
fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
fbi->screen_dma = fbi->map_dma + fbi->video_offset;

/*
* FIXME: this is actually the wrong thing to place in
* smem_start. But fbdev suffers from the problem that
* it needs an API which doesn't exist (in this case,
* dma_writecombine_mmap)
*/
fbi->fb.fix.smem_start = fbi->screen_dma;
fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;

fbi->dma_buff = (void *) fbi->map_cpu;
fbi->dma_buff_phys = fbi->map_dma;
fbi->palette_cpu = (u16 *) fbi->dma_buff->palette;
int size = PAGE_ALIGN(fbi->video_mem_size);

pr_debug("pxafb: palette_mem_size = 0x%08x\n", fbi->palette_size*sizeof(u16));
}

return fbi->map_cpu ? 0 : -ENOMEM;
}
fbi->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
if (fbi->video_mem == NULL)
return -ENOMEM;

static void pxafb_decode_mode_info(struct pxafb_info *fbi,
struct pxafb_mode_info *modes,
unsigned int num_modes)
{
unsigned int i, smemlen;
fbi->video_mem_phys = virt_to_phys(fbi->video_mem);
fbi->video_mem_size = size;

pxafb_setmode(&fbi->fb.var, &modes[0]);
fbi->fb.fix.smem_start = fbi->video_mem_phys;
fbi->fb.fix.smem_len = fbi->video_mem_size;
fbi->fb.screen_base = fbi->video_mem;

for (i = 0; i < num_modes; i++) {
smemlen = modes[i].xres * modes[i].yres * modes[i].bpp / 8;
if (smemlen > fbi->fb.fix.smem_len)
fbi->fb.fix.smem_len = smemlen;
}
return fbi->video_mem ? 0 : -ENOMEM;
}

static void pxafb_decode_mach_info(struct pxafb_info *fbi,
struct pxafb_mach_info *inf)
{
unsigned int lcd_conn = inf->lcd_conn;
struct pxafb_mode_info *m;
int i;

fbi->cmap_inverse = inf->cmap_inverse;
fbi->cmap_static = inf->cmap_static;
Expand Down Expand Up @@ -1371,7 +1319,22 @@ static void pxafb_decode_mach_info(struct pxafb_info *fbi,
fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0;

decode_mode:
pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
pxafb_setmode(&fbi->fb.var, &inf->modes[0]);

/* decide video memory size as follows:
* 1. default to mode of maximum resolution
* 2. allow platform to override
* 3. allow module parameter to override
*/
for (i = 0, m = &inf->modes[0]; i < inf->num_modes; i++, m++)
fbi->video_mem_size = max_t(size_t, fbi->video_mem_size,
m->xres * m->yres * m->bpp / 8);

if (inf->video_mem_size > fbi->video_mem_size)
fbi->video_mem_size = inf->video_mem_size;

if (video_mem_size > fbi->video_mem_size)
fbi->video_mem_size = video_mem_size;
}

static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
Expand Down Expand Up @@ -1499,7 +1462,9 @@ static int __devinit parse_opt(struct device *dev, char *this_opt)

s[0] = '\0';

if (!strncmp(this_opt, "mode:", 5)) {
if (!strncmp(this_opt, "vmem:", 5)) {
video_mem_size = memparse(this_opt + 5, NULL);
} else if (!strncmp(this_opt, "mode:", 5)) {
return parse_opt_mode(dev, this_opt);
} else if (!strncmp(this_opt, "pixclock:", 9)) {
mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
Expand Down Expand Up @@ -1736,12 +1701,20 @@ static int __devinit pxafb_probe(struct platform_device *dev)
goto failed_free_res;
}

/* Initialize video memory */
ret = pxafb_map_video_memory(fbi);
fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
fbi->dma_buff = dma_alloc_coherent(fbi->dev, fbi->dma_buff_size,
&fbi->dma_buff_phys, GFP_KERNEL);
if (fbi->dma_buff == NULL) {
dev_err(&dev->dev, "failed to allocate memory for DMA\n");
ret = -ENOMEM;
goto failed_free_io;
}

ret = pxafb_init_video_memory(fbi);
if (ret) {
dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto failed_free_io;
goto failed_free_dma;
}

irq = platform_get_irq(dev, 0);
Expand Down Expand Up @@ -1811,8 +1784,10 @@ static int __devinit pxafb_probe(struct platform_device *dev)
failed_free_irq:
free_irq(irq, fbi);
failed_free_mem:
dma_free_writecombine(&dev->dev, fbi->map_size,
fbi->map_cpu, fbi->map_dma);
free_pages_exact(fbi->video_mem, fbi->video_mem_size);
failed_free_dma:
dma_free_coherent(&dev->dev, fbi->dma_buff_size,
fbi->dma_buff, fbi->dma_buff_phys);
failed_free_io:
iounmap(fbi->mmio_base);
failed_free_res:
Expand Down Expand Up @@ -1847,8 +1822,10 @@ static int __devexit pxafb_remove(struct platform_device *dev)
irq = platform_get_irq(dev, 0);
free_irq(irq, fbi);

dma_free_writecombine(&dev->dev, fbi->map_size,
fbi->map_cpu, fbi->map_dma);
free_pages_exact(fbi->video_mem, fbi->video_mem_size);

dma_free_writecombine(&dev->dev, fbi->dma_buff_size,
fbi->dma_buff, fbi->dma_buff_phys);

iounmap(fbi->mmio_base);

Expand Down
17 changes: 4 additions & 13 deletions drivers/video/pxafb.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,15 @@ struct pxafb_info {
void __iomem *mmio_base;

struct pxafb_dma_buff *dma_buff;
size_t dma_buff_size;
dma_addr_t dma_buff_phys;
dma_addr_t fdadr[DMA_MAX];

/*
* These are the addresses we mapped
* the framebuffer memory region to.
*/
/* raw memory addresses */
dma_addr_t map_dma; /* physical */
u_char * map_cpu; /* virtual */
u_int map_size;

/* addresses of pieces placed in raw buffer */
u_char * screen_cpu; /* virtual address of frame buffer */
dma_addr_t screen_dma; /* physical address of frame buffer */
void __iomem *video_mem; /* virtual address of frame buffer */
unsigned long video_mem_phys; /* physical address of frame buffer */
size_t video_mem_size; /* size of the frame buffer */
u16 * palette_cpu; /* virtual address of palette memory */
u_int palette_size;
ssize_t video_offset;

u_int lccr0;
u_int lccr3;
Expand Down

0 comments on commit 77e1967

Please sign in to comment.