diff options
author | Eric Miao <eric.miao@marvell.com> | 2008-12-15 22:54:34 -0500 |
---|---|---|
committer | Eric Miao <eric.miao@marvell.com> | 2008-12-29 04:59:16 -0500 |
commit | 77e196752bdd76a0c58ab082658d28c6a90fa40e (patch) | |
tree | 935fbe8b897d8770fff05254c6c91dc0a8058984 | |
parent | 5bfb4093be6ac7b6c06c8e6461d85241654acc61 (diff) |
[ARM] pxafb: allow video memory size to be configurable
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 <eric.miao@marvell.com>
Signed-off-by: Eric Miao <ycmiao@ycmiao-hp520.(none)>
-rw-r--r-- | Documentation/fb/pxafb.txt | 8 | ||||
-rw-r--r-- | arch/arm/mach-pxa/include/mach/pxafb.h | 1 | ||||
-rw-r--r-- | drivers/video/pxafb.c | 131 | ||||
-rw-r--r-- | drivers/video/pxafb.h | 17 |
4 files changed, 65 insertions, 92 deletions
diff --git a/Documentation/fb/pxafb.txt b/Documentation/fb/pxafb.txt index db9b8500b43b..ad94b5ca0095 100644 --- a/Documentation/fb/pxafb.txt +++ b/Documentation/fb/pxafb.txt | |||
@@ -5,9 +5,13 @@ The driver supports the following options, either via | |||
5 | options=<OPTIONS> when modular or video=pxafb:<OPTIONS> when built in. | 5 | options=<OPTIONS> when modular or video=pxafb:<OPTIONS> when built in. |
6 | 6 | ||
7 | For example: | 7 | For example: |
8 | modprobe pxafb options=mode:640x480-8,passive | 8 | modprobe pxafb options=vmem:2M,mode:640x480-8,passive |
9 | or on the kernel command line | 9 | or on the kernel command line |
10 | video=pxafb:mode:640x480-8,passive | 10 | video=pxafb:vmem:2M,mode:640x480-8,passive |
11 | |||
12 | vmem: VIDEO_MEM_SIZE | ||
13 | Amount of video memory to allocate (can be suffixed with K or M | ||
14 | for kilobytes or megabytes) | ||
11 | 15 | ||
12 | mode:XRESxYRES[-BPP] | 16 | mode:XRESxYRES[-BPP] |
13 | XRES == LCCR1_PPL + 1 | 17 | XRES == LCCR1_PPL + 1 |
diff --git a/arch/arm/mach-pxa/include/mach/pxafb.h b/arch/arm/mach-pxa/include/mach/pxafb.h index 4201a889ff4e..6932720ba04e 100644 --- a/arch/arm/mach-pxa/include/mach/pxafb.h +++ b/arch/arm/mach-pxa/include/mach/pxafb.h | |||
@@ -113,6 +113,7 @@ struct pxafb_mach_info { | |||
113 | unsigned int num_modes; | 113 | unsigned int num_modes; |
114 | 114 | ||
115 | unsigned int lcd_conn; | 115 | unsigned int lcd_conn; |
116 | unsigned long video_mem_size; | ||
116 | 117 | ||
117 | u_int fixed_modes:1, | 118 | u_int fixed_modes:1, |
118 | cmap_inverse:1, | 119 | cmap_inverse:1, |
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index ab689597f259..25bf4b8b6b53 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -72,6 +72,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, | |||
72 | struct pxafb_info *); | 72 | struct pxafb_info *); |
73 | static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); | 73 | static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); |
74 | 74 | ||
75 | static unsigned long video_mem_size = 0; | ||
76 | |||
75 | static inline unsigned long | 77 | static inline unsigned long |
76 | lcd_readl(struct pxafb_info *fbi, unsigned int off) | 78 | lcd_readl(struct pxafb_info *fbi, unsigned int off) |
77 | { | 79 | { |
@@ -498,20 +500,6 @@ static int pxafb_blank(int blank, struct fb_info *info) | |||
498 | return 0; | 500 | return 0; |
499 | } | 501 | } |
500 | 502 | ||
501 | static int pxafb_mmap(struct fb_info *info, | ||
502 | struct vm_area_struct *vma) | ||
503 | { | ||
504 | struct pxafb_info *fbi = (struct pxafb_info *)info; | ||
505 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT; | ||
506 | |||
507 | if (off < info->fix.smem_len) { | ||
508 | vma->vm_pgoff += fbi->video_offset / PAGE_SIZE; | ||
509 | return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu, | ||
510 | fbi->map_dma, fbi->map_size); | ||
511 | } | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | static struct fb_ops pxafb_ops = { | 503 | static struct fb_ops pxafb_ops = { |
516 | .owner = THIS_MODULE, | 504 | .owner = THIS_MODULE, |
517 | .fb_check_var = pxafb_check_var, | 505 | .fb_check_var = pxafb_check_var, |
@@ -521,7 +509,6 @@ static struct fb_ops pxafb_ops = { | |||
521 | .fb_copyarea = cfb_copyarea, | 509 | .fb_copyarea = cfb_copyarea, |
522 | .fb_imageblit = cfb_imageblit, | 510 | .fb_imageblit = cfb_imageblit, |
523 | .fb_blank = pxafb_blank, | 511 | .fb_blank = pxafb_blank, |
524 | .fb_mmap = pxafb_mmap, | ||
525 | }; | 512 | }; |
526 | 513 | ||
527 | /* | 514 | /* |
@@ -614,7 +601,7 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, | |||
614 | dma_desc = &fbi->dma_buff->dma_desc[dma]; | 601 | dma_desc = &fbi->dma_buff->dma_desc[dma]; |
615 | dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]); | 602 | dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]); |
616 | 603 | ||
617 | dma_desc->fsadr = fbi->screen_dma + offset; | 604 | dma_desc->fsadr = fbi->video_mem_phys + offset; |
618 | dma_desc->fidr = 0; | 605 | dma_desc->fidr = 0; |
619 | dma_desc->ldcmd = size; | 606 | dma_desc->ldcmd = size; |
620 | 607 | ||
@@ -1267,69 +1254,30 @@ static int pxafb_resume(struct platform_device *dev) | |||
1267 | #define pxafb_resume NULL | 1254 | #define pxafb_resume NULL |
1268 | #endif | 1255 | #endif |
1269 | 1256 | ||
1270 | /* | 1257 | static int __devinit pxafb_init_video_memory(struct pxafb_info *fbi) |
1271 | * pxafb_map_video_memory(): | ||
1272 | * Allocates the DRAM memory for the frame buffer. This buffer is | ||
1273 | * remapped into a non-cached, non-buffered, memory region to | ||
1274 | * allow palette and pixel writes to occur without flushing the | ||
1275 | * cache. Once this area is remapped, all virtual memory | ||
1276 | * access to the video memory should occur at the new region. | ||
1277 | */ | ||
1278 | static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi) | ||
1279 | { | 1258 | { |
1280 | /* | 1259 | int size = PAGE_ALIGN(fbi->video_mem_size); |
1281 | * We reserve one page for the palette, plus the size | ||
1282 | * of the framebuffer. | ||
1283 | */ | ||
1284 | fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff)); | ||
1285 | fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset); | ||
1286 | fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, | ||
1287 | &fbi->map_dma, GFP_KERNEL); | ||
1288 | |||
1289 | if (fbi->map_cpu) { | ||
1290 | /* prevent initial garbage on screen */ | ||
1291 | memset(fbi->map_cpu, 0, fbi->map_size); | ||
1292 | fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset; | ||
1293 | fbi->screen_dma = fbi->map_dma + fbi->video_offset; | ||
1294 | |||
1295 | /* | ||
1296 | * FIXME: this is actually the wrong thing to place in | ||
1297 | * smem_start. But fbdev suffers from the problem that | ||
1298 | * it needs an API which doesn't exist (in this case, | ||
1299 | * dma_writecombine_mmap) | ||
1300 | */ | ||
1301 | fbi->fb.fix.smem_start = fbi->screen_dma; | ||
1302 | fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; | ||
1303 | |||
1304 | fbi->dma_buff = (void *) fbi->map_cpu; | ||
1305 | fbi->dma_buff_phys = fbi->map_dma; | ||
1306 | fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; | ||
1307 | 1260 | ||
1308 | pr_debug("pxafb: palette_mem_size = 0x%08x\n", fbi->palette_size*sizeof(u16)); | 1261 | fbi->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO); |
1309 | } | 1262 | if (fbi->video_mem == NULL) |
1310 | 1263 | return -ENOMEM; | |
1311 | return fbi->map_cpu ? 0 : -ENOMEM; | ||
1312 | } | ||
1313 | 1264 | ||
1314 | static void pxafb_decode_mode_info(struct pxafb_info *fbi, | 1265 | fbi->video_mem_phys = virt_to_phys(fbi->video_mem); |
1315 | struct pxafb_mode_info *modes, | 1266 | fbi->video_mem_size = size; |
1316 | unsigned int num_modes) | ||
1317 | { | ||
1318 | unsigned int i, smemlen; | ||
1319 | 1267 | ||
1320 | pxafb_setmode(&fbi->fb.var, &modes[0]); | 1268 | fbi->fb.fix.smem_start = fbi->video_mem_phys; |
1269 | fbi->fb.fix.smem_len = fbi->video_mem_size; | ||
1270 | fbi->fb.screen_base = fbi->video_mem; | ||
1321 | 1271 | ||
1322 | for (i = 0; i < num_modes; i++) { | 1272 | return fbi->video_mem ? 0 : -ENOMEM; |
1323 | smemlen = modes[i].xres * modes[i].yres * modes[i].bpp / 8; | ||
1324 | if (smemlen > fbi->fb.fix.smem_len) | ||
1325 | fbi->fb.fix.smem_len = smemlen; | ||
1326 | } | ||
1327 | } | 1273 | } |
1328 | 1274 | ||
1329 | static void pxafb_decode_mach_info(struct pxafb_info *fbi, | 1275 | static void pxafb_decode_mach_info(struct pxafb_info *fbi, |
1330 | struct pxafb_mach_info *inf) | 1276 | struct pxafb_mach_info *inf) |
1331 | { | 1277 | { |
1332 | unsigned int lcd_conn = inf->lcd_conn; | 1278 | unsigned int lcd_conn = inf->lcd_conn; |
1279 | struct pxafb_mode_info *m; | ||
1280 | int i; | ||
1333 | 1281 | ||
1334 | fbi->cmap_inverse = inf->cmap_inverse; | 1282 | fbi->cmap_inverse = inf->cmap_inverse; |
1335 | fbi->cmap_static = inf->cmap_static; | 1283 | fbi->cmap_static = inf->cmap_static; |
@@ -1371,7 +1319,22 @@ static void pxafb_decode_mach_info(struct pxafb_info *fbi, | |||
1371 | fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0; | 1319 | fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0; |
1372 | 1320 | ||
1373 | decode_mode: | 1321 | decode_mode: |
1374 | pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes); | 1322 | pxafb_setmode(&fbi->fb.var, &inf->modes[0]); |
1323 | |||
1324 | /* decide video memory size as follows: | ||
1325 | * 1. default to mode of maximum resolution | ||
1326 | * 2. allow platform to override | ||
1327 | * 3. allow module parameter to override | ||
1328 | */ | ||
1329 | for (i = 0, m = &inf->modes[0]; i < inf->num_modes; i++, m++) | ||
1330 | fbi->video_mem_size = max_t(size_t, fbi->video_mem_size, | ||
1331 | m->xres * m->yres * m->bpp / 8); | ||
1332 | |||
1333 | if (inf->video_mem_size > fbi->video_mem_size) | ||
1334 | fbi->video_mem_size = inf->video_mem_size; | ||
1335 | |||
1336 | if (video_mem_size > fbi->video_mem_size) | ||
1337 | fbi->video_mem_size = video_mem_size; | ||
1375 | } | 1338 | } |
1376 | 1339 | ||
1377 | static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev) | 1340 | static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev) |
@@ -1499,7 +1462,9 @@ static int __devinit parse_opt(struct device *dev, char *this_opt) | |||
1499 | 1462 | ||
1500 | s[0] = '\0'; | 1463 | s[0] = '\0'; |
1501 | 1464 | ||
1502 | if (!strncmp(this_opt, "mode:", 5)) { | 1465 | if (!strncmp(this_opt, "vmem:", 5)) { |
1466 | video_mem_size = memparse(this_opt + 5, NULL); | ||
1467 | } else if (!strncmp(this_opt, "mode:", 5)) { | ||
1503 | return parse_opt_mode(dev, this_opt); | 1468 | return parse_opt_mode(dev, this_opt); |
1504 | } else if (!strncmp(this_opt, "pixclock:", 9)) { | 1469 | } else if (!strncmp(this_opt, "pixclock:", 9)) { |
1505 | mode->pixclock = simple_strtoul(this_opt+9, NULL, 0); | 1470 | mode->pixclock = simple_strtoul(this_opt+9, NULL, 0); |
@@ -1736,12 +1701,20 @@ static int __devinit pxafb_probe(struct platform_device *dev) | |||
1736 | goto failed_free_res; | 1701 | goto failed_free_res; |
1737 | } | 1702 | } |
1738 | 1703 | ||
1739 | /* Initialize video memory */ | 1704 | fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff)); |
1740 | ret = pxafb_map_video_memory(fbi); | 1705 | fbi->dma_buff = dma_alloc_coherent(fbi->dev, fbi->dma_buff_size, |
1706 | &fbi->dma_buff_phys, GFP_KERNEL); | ||
1707 | if (fbi->dma_buff == NULL) { | ||
1708 | dev_err(&dev->dev, "failed to allocate memory for DMA\n"); | ||
1709 | ret = -ENOMEM; | ||
1710 | goto failed_free_io; | ||
1711 | } | ||
1712 | |||
1713 | ret = pxafb_init_video_memory(fbi); | ||
1741 | if (ret) { | 1714 | if (ret) { |
1742 | dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret); | 1715 | dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret); |
1743 | ret = -ENOMEM; | 1716 | ret = -ENOMEM; |
1744 | goto failed_free_io; | 1717 | goto failed_free_dma; |
1745 | } | 1718 | } |
1746 | 1719 | ||
1747 | irq = platform_get_irq(dev, 0); | 1720 | irq = platform_get_irq(dev, 0); |
@@ -1811,8 +1784,10 @@ failed_free_cmap: | |||
1811 | failed_free_irq: | 1784 | failed_free_irq: |
1812 | free_irq(irq, fbi); | 1785 | free_irq(irq, fbi); |
1813 | failed_free_mem: | 1786 | failed_free_mem: |
1814 | dma_free_writecombine(&dev->dev, fbi->map_size, | 1787 | free_pages_exact(fbi->video_mem, fbi->video_mem_size); |
1815 | fbi->map_cpu, fbi->map_dma); | 1788 | failed_free_dma: |
1789 | dma_free_coherent(&dev->dev, fbi->dma_buff_size, | ||
1790 | fbi->dma_buff, fbi->dma_buff_phys); | ||
1816 | failed_free_io: | 1791 | failed_free_io: |
1817 | iounmap(fbi->mmio_base); | 1792 | iounmap(fbi->mmio_base); |
1818 | failed_free_res: | 1793 | failed_free_res: |
@@ -1847,8 +1822,10 @@ static int __devexit pxafb_remove(struct platform_device *dev) | |||
1847 | irq = platform_get_irq(dev, 0); | 1822 | irq = platform_get_irq(dev, 0); |
1848 | free_irq(irq, fbi); | 1823 | free_irq(irq, fbi); |
1849 | 1824 | ||
1850 | dma_free_writecombine(&dev->dev, fbi->map_size, | 1825 | free_pages_exact(fbi->video_mem, fbi->video_mem_size); |
1851 | fbi->map_cpu, fbi->map_dma); | 1826 | |
1827 | dma_free_writecombine(&dev->dev, fbi->dma_buff_size, | ||
1828 | fbi->dma_buff, fbi->dma_buff_phys); | ||
1852 | 1829 | ||
1853 | iounmap(fbi->mmio_base); | 1830 | iounmap(fbi->mmio_base); |
1854 | 1831 | ||
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index d8eb93fa03a3..0981938682ef 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h | |||
@@ -69,24 +69,15 @@ struct pxafb_info { | |||
69 | void __iomem *mmio_base; | 69 | void __iomem *mmio_base; |
70 | 70 | ||
71 | struct pxafb_dma_buff *dma_buff; | 71 | struct pxafb_dma_buff *dma_buff; |
72 | size_t dma_buff_size; | ||
72 | dma_addr_t dma_buff_phys; | 73 | dma_addr_t dma_buff_phys; |
73 | dma_addr_t fdadr[DMA_MAX]; | 74 | dma_addr_t fdadr[DMA_MAX]; |
74 | 75 | ||
75 | /* | 76 | void __iomem *video_mem; /* virtual address of frame buffer */ |
76 | * These are the addresses we mapped | 77 | unsigned long video_mem_phys; /* physical address of frame buffer */ |
77 | * the framebuffer memory region to. | 78 | size_t video_mem_size; /* size of the frame buffer */ |
78 | */ | ||
79 | /* raw memory addresses */ | ||
80 | dma_addr_t map_dma; /* physical */ | ||
81 | u_char * map_cpu; /* virtual */ | ||
82 | u_int map_size; | ||
83 | |||
84 | /* addresses of pieces placed in raw buffer */ | ||
85 | u_char * screen_cpu; /* virtual address of frame buffer */ | ||
86 | dma_addr_t screen_dma; /* physical address of frame buffer */ | ||
87 | u16 * palette_cpu; /* virtual address of palette memory */ | 79 | u16 * palette_cpu; /* virtual address of palette memory */ |
88 | u_int palette_size; | 80 | u_int palette_size; |
89 | ssize_t video_offset; | ||
90 | 81 | ||
91 | u_int lccr0; | 82 | u_int lccr0; |
92 | u_int lccr3; | 83 | u_int lccr3; |